Compare commits

..

12 Commits

Author SHA1 Message Date
sercan
d146a92c79 Merge remote-tracking branch 'origin/demo' into starter 2021-05-15 13:18:13 +03:00
sercan
27b6858b76 Merge remote-tracking branch 'origin/demo' into starter 2021-05-06 17:12:50 +03:00
sercan
fcfba4c9e4 Merge remote-tracking branch 'origin/demo' into starter 2021-04-30 19:40:30 +03:00
sercan
40894e0aa3 Merge remote-tracking branch 'origin/demo' into starter
# Conflicts:
#	src/app/app.routing.ts
#	src/app/mock-api/common/navigation/data.ts
#	src/app/modules/admin/apps/academy/academy.service.ts
#	src/app/modules/admin/apps/academy/details/details.component.html
#	src/app/modules/admin/apps/academy/list/list.component.html
#	src/app/modules/admin/apps/mailbox/list/list.component.ts
#	src/app/modules/admin/docs/changelog/changelog.ts
#	src/app/modules/admin/pages/pricing/modern/modern.component.html
#	src/app/modules/admin/pages/pricing/simple/simple.component.html
#	src/app/modules/admin/pages/pricing/single/single.component.html
#	src/app/modules/admin/pages/pricing/table/table.component.html
2021-04-30 19:40:07 +03:00
sercan
8dcf21cb1a Merge remote-tracking branch 'origin/demo' into starter 2021-04-26 10:23:15 +03:00
sercan
d917f03883 Merge remote-tracking branch 'origin/demo' into starter 2021-04-26 10:20:06 +03:00
sercan
0f2ddbda83 Merge remote-tracking branch 'origin/demo' into starter
# Conflicts:
#	src/app/mock-api/common/navigation/data.ts
#	src/app/modules/admin/docs/changelog/changelog.ts
2021-04-26 09:56:44 +03:00
sercan
fa0d74504b Merge remote-tracking branch 'origin/demo' into starter 2021-04-26 09:56:29 +03:00
sercan
ad2b19a07a Merge remote-tracking branch 'origin/demo' into starter
# Conflicts:
#	src/app/app.routing.ts
#	src/app/mock-api/common/navigation/data.ts
#	src/app/modules/admin/apps/contacts/details/details.component.html
#	src/app/modules/admin/apps/file-manager/list/list.component.html
#	src/app/modules/admin/apps/file-manager/list/list.component.ts
#	src/app/modules/landing/home/home.component.html
2021-04-26 09:31:42 +03:00
sercan
4bf11591a2 (Assets) Added avatar images back 2021-04-19 13:08:24 +03:00
sercan
f45a605b4e Preparing the starter 2021-04-15 17:43:28 +03:00
sercan
c150a8902c Starter 2021-04-15 17:23:49 +03:00
999 changed files with 12767 additions and 98711 deletions

View File

@@ -14,3 +14,4 @@ last 2 Edge major versions
last 2 Safari major versions last 2 Safari major versions
last 2 iOS major versions last 2 iOS major versions
Firefox ESR Firefox ESR
not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.

View File

@@ -16,7 +16,8 @@
], ],
"parserOptions": { "parserOptions": {
"project": [ "project": [
"tsconfig.json" "tsconfig.json",
"e2e/tsconfig.json"
], ],
"createDefaultProgram": true "createDefaultProgram": true
}, },
@@ -43,7 +44,6 @@
} }
], ],
"@typescript-eslint/dot-notation": "off", "@typescript-eslint/dot-notation": "off",
"@typescript-eslint/explicit-function-return-type": "error",
"@typescript-eslint/explicit-member-accessibility": [ "@typescript-eslint/explicit-member-accessibility": [
"off", "off",
{ {

1
.gitignore vendored
View File

@@ -31,7 +31,6 @@ chrome-profiler-events*.json
.history/* .history/*
# misc # misc
/.angular/cache
/.sass-cache /.sass-cache
/connect.lock /connect.lock
/coverage /coverage

1
.npmrc
View File

@@ -1 +0,0 @@
legacy-peer-deps=true

2
.nvmrc
View File

@@ -1 +1 @@
16 12

View File

@@ -2,9 +2,6 @@
// @ 3rd party credits // @ 3rd party credits
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
// Flags
https://github.com/Yummygum/flagpack-core
// Icons // Icons
Material - https://material.io/tools/icons Material - https://material.io/tools/icons
Feather - https://feathericons.com/ Feather - https://feathericons.com/

View File

@@ -12,7 +12,7 @@ Run `ng generate component component-name` to generate a new component. You can
## Build ## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
## Running unit tests ## Running unit tests
@@ -20,7 +20,7 @@ Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.
## Running end-to-end tests ## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. Run `ng e2e` to execute the end-to-end tests via a platform of your choice.
## Further help ## Further help

View File

@@ -1,12 +1,6 @@
{ {
"$schema": "./node_modules/@angular/cli/lib/config/schema.json", "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1, "version": 1,
"cli": {
"defaultCollection": "@angular-eslint/schematics",
"cache": {
"enabled": false
}
},
"newProjectRoot": "projects", "newProjectRoot": "projects",
"projects": { "projects": {
"fuse": { "fuse": {
@@ -66,13 +60,13 @@
"budgets": [ "budgets": [
{ {
"type": "initial", "type": "initial",
"maximumWarning": "3mb", "maximumWarning": "5mb",
"maximumError": "5mb" "maximumError": "8mb"
}, },
{ {
"type": "anyComponentStyle", "type": "anyComponentStyle",
"maximumWarning": "75kb", "maximumWarning": "100kb",
"maximumError": "90kb" "maximumError": "150kb"
} }
], ],
"fileReplacements": [ "fileReplacements": [
@@ -126,7 +120,7 @@
"src/assets" "src/assets"
], ],
"styles": [ "styles": [
"src/styles/styles.scss" "src/styles.scss"
], ],
"scripts": [] "scripts": []
} }
@@ -139,9 +133,24 @@
"src/**/*.html" "src/**/*.html"
] ]
} }
},
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "fuse:serve"
},
"configurations": {
"production": {
"devServerTarget": "fuse:serve:production"
}
}
} }
} }
} }
}, },
"defaultProject": "fuse" "defaultProject": "fuse",
"cli": {
"defaultCollection": "@angular-eslint/schematics"
}
} }

View File

@@ -26,7 +26,7 @@ module.exports = function (config)
suppressAll: true // removes the duplicated traces suppressAll: true // removes the duplicated traces
}, },
coverageReporter : { coverageReporter : {
dir : require('path').join(__dirname, './coverage/fuse'), dir : require('path').join(__dirname, './coverage/angular12'),
subdir : '.', subdir : '.',
reporters: [ reporters: [
{type: 'html'}, {type: 'html'},

26905
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,81 +1,91 @@
{ {
"name": "@fuse/demo", "name": "@fuse/demo",
"version": "14.1.1", "version": "13.0.0",
"description": "Fuse - Angular Admin Template and Starter Project",
"author": "https://themeforest.net/user/srcn",
"license": "https://themeforest.net/licenses/standard", "license": "https://themeforest.net/licenses/standard",
"private": true, "private": true,
"scripts": { "scripts": {
"ng": "ng", "ng": "ng",
"start": "ng serve", "start": "ng serve",
"build": "ng build", "build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test", "test": "ng test",
"lint": "ng lint" "lint": "ng lint",
"e2e": "ng e2e"
}, },
"dependencies": { "dependencies": {
"@angular/animations": "13.1.1", "@angular/animations": "12.0.0",
"@angular/cdk": "13.1.1", "@angular/cdk": "12.0.0",
"@angular/common": "13.1.1", "@angular/common": "12.0.0",
"@angular/compiler": "13.1.1", "@angular/compiler": "12.0.0",
"@angular/core": "13.1.1", "@angular/core": "12.0.0",
"@angular/forms": "13.1.1", "@angular/forms": "12.0.0",
"@angular/material": "13.1.1", "@angular/material": "12.0.0",
"@angular/material-moment-adapter": "13.1.1", "@angular/material-moment-adapter": "12.0.0",
"@angular/platform-browser": "13.1.1", "@angular/platform-browser": "12.0.0",
"@angular/platform-browser-dynamic": "13.1.1", "@angular/platform-browser-dynamic": "12.0.0",
"@angular/router": "13.1.1", "@angular/router": "12.0.0",
"@ngneat/transloco": "3.1.1", "@fullcalendar/angular": "4.4.5-beta",
"apexcharts": "3.32.1", "@fullcalendar/core": "4.4.2",
"@fullcalendar/daygrid": "4.4.2",
"@fullcalendar/interaction": "4.4.2",
"@fullcalendar/list": "4.4.2",
"@fullcalendar/moment": "4.4.2",
"@fullcalendar/rrule": "4.4.2",
"@fullcalendar/timegrid": "4.4.2",
"apexcharts": "3.26.2",
"crypto-js": "3.3.0", "crypto-js": "3.3.0",
"highlight.js": "11.3.1", "highlight.js": "10.7.2",
"lodash-es": "4.17.21", "lodash-es": "4.17.21",
"moment": "2.29.1", "moment": "2.29.1",
"ng-apexcharts": "1.6.0", "ng-apexcharts": "1.5.9",
"ngx-markdown": "13.0.0", "ngx-markdown": "11.1.3",
"ngx-quill": "16.1.1", "ngx-quill": "14.0.0",
"perfect-scrollbar": "1.5.3", "perfect-scrollbar": "1.5.1",
"quill": "1.3.7", "quill": "1.3.7",
"rxjs": "7.5.1", "rrule": "2.6.8",
"tslib": "2.3.1", "rxjs": "6.6.7",
"tslib": "2.2.0",
"web-animations-js": "2.3.2",
"zone.js": "0.11.4" "zone.js": "0.11.4"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "13.1.2", "@angular-devkit/build-angular": "12.0.0",
"@angular-eslint/builder": "13.0.1", "@angular-eslint/builder": "12.0.0",
"@angular-eslint/eslint-plugin": "13.0.1", "@angular-eslint/eslint-plugin": "12.0.0",
"@angular-eslint/eslint-plugin-template": "13.0.1", "@angular-eslint/eslint-plugin-template": "12.0.0",
"@angular-eslint/schematics": "13.0.1", "@angular-eslint/schematics": "12.0.0",
"@angular-eslint/template-parser": "13.0.1", "@angular-eslint/template-parser": "12.0.0",
"@angular/cli": "13.1.2", "@angular/cli": "12.0.0",
"@angular/compiler-cli": "13.1.1", "@angular/compiler-cli": "12.0.0",
"@tailwindcss/aspect-ratio": "0.4.0", "@angular/language-service": "12.0.0",
"@tailwindcss/line-clamp": "0.3.0", "@tailwindcss/aspect-ratio": "0.2.0",
"@tailwindcss/typography": "0.5.0", "@tailwindcss/line-clamp": "0.2.0",
"@tailwindcss/typography": "0.4.0",
"@types/chroma-js": "2.1.3", "@types/chroma-js": "2.1.3",
"@types/crypto-js": "3.1.47", "@types/crypto-js": "3.1.47",
"@types/highlight.js": "10.1.0", "@types/highlight.js": "10.1.0",
"@types/jasmine": "3.10.2", "@types/jasmine": "3.6.11",
"@types/lodash": "4.14.178", "@types/lodash": "4.14.169",
"@types/lodash-es": "4.17.5", "@types/lodash-es": "4.17.4",
"@types/node": "12.20.38", "@types/node": "12.20.13",
"@typescript-eslint/eslint-plugin": "5.8.1", "@typescript-eslint/eslint-plugin": "4.23.0",
"@typescript-eslint/parser": "5.8.1", "@typescript-eslint/parser": "4.23.0",
"autoprefixer": "10.4.1", "autoprefixer": "10.2.5",
"chroma-js": "2.1.2", "chroma-js": "2.1.1",
"eslint": "8.6.0", "eslint": "7.26.0",
"eslint-plugin-import": "2.25.3", "eslint-plugin-import": "2.23.0",
"eslint-plugin-jsdoc": "37.5.0", "eslint-plugin-jsdoc": "34.2.2",
"eslint-plugin-prefer-arrow": "1.2.3", "eslint-plugin-prefer-arrow": "1.2.3",
"jasmine-core": "3.10.1", "jasmine-core": "3.7.1",
"karma": "6.3.9", "jasmine-spec-reporter": "5.0.2",
"karma": "6.3.2",
"karma-chrome-launcher": "3.1.0", "karma-chrome-launcher": "3.1.0",
"karma-coverage": "2.1.0", "karma-coverage": "2.0.3",
"karma-jasmine": "4.0.1", "karma-jasmine": "4.0.1",
"karma-jasmine-html-reporter": "1.7.0", "karma-jasmine-html-reporter": "1.6.0",
"lodash": "4.17.21", "lodash": "4.17.21",
"postcss": "8.4.5", "postcss": "8.2.15",
"tailwindcss": "3.0.8", "protractor": "7.0.0",
"typescript": "4.5.4" "tailwindcss": "2.1.2",
"typescript": "4.2.4"
} }
} }

View File

@@ -1 +1 @@
export * from '@fuse/animations/public-api'; export * from './public-api';

View File

@@ -1,8 +1,8 @@
import { expandCollapse } from '@fuse/animations/expand-collapse'; import { expandCollapse } from './expand-collapse';
import { fadeIn, fadeInBottom, fadeInLeft, fadeInRight, fadeInTop, fadeOut, fadeOutBottom, fadeOutLeft, fadeOutRight, fadeOutTop } from '@fuse/animations/fade'; import { fadeIn, fadeInBottom, fadeInLeft, fadeInRight, fadeInTop, fadeOut, fadeOutBottom, fadeOutLeft, fadeOutRight, fadeOutTop } from './fade';
import { shake } from '@fuse/animations/shake'; import { shake } from './shake';
import { slideInBottom, slideInLeft, slideInRight, slideInTop, slideOutBottom, slideOutLeft, slideOutRight, slideOutTop } from '@fuse/animations/slide'; import { slideInBottom, slideInLeft, slideInRight, slideInTop, slideOutBottom, slideOutLeft, slideOutRight, slideOutTop } from './slide';
import { zoomIn, zoomOut } from '@fuse/animations/zoom'; import { zoomIn, zoomOut } from './zoom';
export const fuseAnimations = [ export const fuseAnimations = [
expandCollapse, expandCollapse,

View File

@@ -1,5 +1,6 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, HostBinding, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, ViewEncapsulation } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, HostBinding, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { filter, Subject, takeUntil } from 'rxjs'; import { Subject } from 'rxjs';
import { filter, takeUntil } from 'rxjs/operators';
import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion'; import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';
import { fuseAnimations } from '@fuse/animations'; import { fuseAnimations } from '@fuse/animations';
import { FuseAlertAppearance, FuseAlertType } from '@fuse/components/alert/alert.types'; import { FuseAlertAppearance, FuseAlertType } from '@fuse/components/alert/alert.types';
@@ -144,7 +145,7 @@ export class FuseAlertComponent implements OnChanges, OnInit, OnDestroy
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(null); this._unsubscribeAll.next();
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }

View File

@@ -0,0 +1,101 @@
<div
class="range"
(click)="openPickerPanel()"
#pickerPanelOrigin>
<div class="start">
<div class="date">{{range.startDate}}</div>
<div
class="time"
*ngIf="range.startTime">{{range.startTime}}</div>
</div>
<div class="separator">-</div>
<div class="end">
<div class="date">{{range.endDate}}</div>
<div
class="time"
*ngIf="range.endTime">{{range.endTime}}</div>
</div>
</div>
<ng-template #pickerPanel>
<!-- Start -->
<div class="start">
<div class="month">
<div class="month-header">
<button
class="previous-button"
mat-icon-button
(click)="prev()"
tabindex="1">
<mat-icon [svgIcon]="'heroicons_outline:chevron-left'"></mat-icon>
</button>
<div class="month-label">{{getMonthLabel(1)}}</div>
</div>
<mat-month-view
[(activeDate)]="activeDates.month1"
[dateFilter]="dateFilter()"
[dateClass]="dateClass()"
(click)="$event.stopImmediatePropagation()"
(selectedChange)="onSelectedDateChange($event)"
#matMonthView1>
</mat-month-view>
</div>
<mat-form-field
class="fuse-mat-no-subscript time start-time"
*ngIf="timeRange">
<input
matInput
[autocomplete]="'off'"
[formControl]="startTimeFormControl"
(blur)="updateStartTime($event)"
tabindex="3">
<mat-label>Start time</mat-label>
</mat-form-field>
</div>
<!-- End -->
<div class="end">
<div class="month">
<div class="month-header">
<div class="month-label">{{getMonthLabel(2)}}</div>
<button
class="next-button"
mat-icon-button
(click)="next()"
tabindex="2">
<mat-icon [svgIcon]="'heroicons_outline:chevron-right'"></mat-icon>
</button>
</div>
<mat-month-view
[(activeDate)]="activeDates.month2"
[dateFilter]="dateFilter()"
[dateClass]="dateClass()"
(click)="$event.stopImmediatePropagation()"
(selectedChange)="onSelectedDateChange($event)"
#matMonthView2>
</mat-month-view>
</div>
<mat-form-field
class="fuse-mat-no-subscript time end-time"
*ngIf="timeRange">
<input
matInput
[formControl]="endTimeFormControl"
(blur)="updateEndTime($event)"
tabindex="4">
<mat-label>End time</mat-label>
</mat-form-field>
</div>
</ng-template>

View File

@@ -0,0 +1,292 @@
/* Variables */
$body-cell-padding: 2px;
fuse-date-range {
display: flex;
.range {
display: flex;
align-items: center;
height: 48px;
min-height: 48px;
max-height: 48px;
cursor: pointer;
.start,
.end {
display: flex;
align-items: center;
height: 100%;
padding: 0 16px;
border-radius: 6px;
border-width: 1px;
line-height: 1;
@apply shadow-sm border-gray-300 dark:bg-black dark:bg-opacity-5 dark:border-gray-500;
.date {
white-space: nowrap;
+ .time {
margin-left: 8px;
}
}
.time {
white-space: nowrap;
}
}
.separator {
margin: 0 2px;
@screen sm {
margin: 0 12px;
}
}
}
}
.fuse-date-range-panel {
border-radius: 4px;
padding: 24px;
@apply shadow-2xl bg-card;
.start,
.end {
display: flex;
flex-direction: column;
.month {
max-width: 196px;
min-width: 196px;
width: 196px;
.month-header {
position: relative;
display: flex;
align-items: center;
justify-content: center;
height: 32px;
margin-bottom: 16px;
.previous-button,
.next-button {
position: absolute;
width: 24px !important;
height: 24px !important;
min-height: 24px !important;
max-height: 24px !important;
line-height: 24px !important;
.mat-icon {
@apply icon-size-5;
}
}
.previous-button {
left: 0;
}
.next-button {
right: 0;
}
.month-label {
font-weight: 500;
@apply text-secondary;
}
}
mat-month-view {
display: flex;
min-height: 188px;
.mat-calendar-table {
width: 100%;
border-collapse: collapse;
tbody {
tr {
&[aria-hidden=true] {
display: none !important;
}
&:first-child {
td:first-child {
&[aria-hidden=true] {
visibility: hidden;
pointer-events: none;
opacity: 0;
}
}
}
td,
td:hover {
&.fuse-date-range {
&:before {
@apply bg-primary-200;
}
.mat-calendar-body-cell-content {
background-color: transparent;
}
}
&.fuse-date-range-start,
&.fuse-date-range-end {
.mat-calendar-body-cell-content {
@apply bg-primary text-on-primary;
}
}
.mat-calendar-body-today {
border: none;
}
}
td.mat-calendar-body-cell {
width: 28px !important;
height: 28px !important;
padding: $body-cell-padding !important;
&.fuse-date-range {
position: relative;
&:before {
content: '';
position: absolute;
top: $body-cell-padding;
right: 0;
bottom: $body-cell-padding;
left: 0;
}
&.fuse-date-range-start {
&:before {
left: $body-cell-padding;
border-radius: 999px 0 0 999px;
}
&.fuse-date-range-end,
&:last-child {
&:before {
right: $body-cell-padding;
border-radius: 999px;
}
}
}
&.fuse-date-range-end {
&:before {
right: $body-cell-padding;
border-radius: 0 999px 999px 0;
}
&:first-child {
&:before {
left: $body-cell-padding;
border-radius: 999px;
}
}
}
&:first-child {
&:before {
border-radius: 999px 0 0 999px;
}
}
&:last-child {
&:before {
border-radius: 0 999px 999px 0;
}
}
}
.mat-calendar-body-cell-content {
position: relative;
top: 0;
left: 0;
width: 24px;
height: 24px;
font-size: 12px;
}
}
td.mat-calendar-body-label {
+ td.mat-calendar-body-cell {
&.fuse-date-range {
&:before {
border-radius: 999px 0 0 999px;
}
&.fuse-date-range-start {
&.fuse-date-range-end {
border-radius: 999px;
}
}
&.fuse-date-range-end {
&:before {
left: $body-cell-padding;
border-radius: 999px;
}
}
}
}
}
}
}
}
}
}
.time {
width: 100%;
max-width: 196px;
}
}
.start {
align-items: flex-start;
margin-right: 20px;
.month {
.month-label {
margin-left: 8px;
}
}
}
.end {
align-items: flex-end;
margin-left: 20px;
.month {
.month-label {
margin-right: 8px;
}
}
}
}

View File

@@ -0,0 +1,682 @@
import { ChangeDetectorRef, Component, ElementRef, EventEmitter, forwardRef, HostBinding, Input, OnDestroy, OnInit, Output, Renderer2, TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation } from '@angular/core';
import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
import { Overlay } from '@angular/cdk/overlay';
import { TemplatePortal } from '@angular/cdk/portal';
import { MatCalendarCellCssClasses, MatMonthView } from '@angular/material/datepicker';
import { Subject } from 'rxjs';
import * as moment from 'moment';
import { Moment } from 'moment';
@Component({
selector : 'fuse-date-range',
templateUrl : './date-range.component.html',
styleUrls : ['./date-range.component.scss'],
encapsulation: ViewEncapsulation.None,
exportAs : 'fuseDateRange',
providers : [
{
provide : NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => FuseDateRangeComponent),
multi : true
}
]
})
export class FuseDateRangeComponent implements ControlValueAccessor, OnInit, OnDestroy
{
@Output() readonly rangeChanged: EventEmitter<{ start: string; end: string }> = new EventEmitter<{ start: string; end: string }>();
@ViewChild('matMonthView1') private _matMonthView1: MatMonthView<any>;
@ViewChild('matMonthView2') private _matMonthView2: MatMonthView<any>;
@ViewChild('pickerPanelOrigin', {read: ElementRef}) private _pickerPanelOrigin: ElementRef;
@ViewChild('pickerPanel') private _pickerPanel: TemplateRef<any>;
@HostBinding('class.fuse-date-range') private _defaultClassNames = true;
activeDates: { month1: Moment | null; month2: Moment | null } = {
month1: null,
month2: null
};
setWhichDate: 'start' | 'end' = 'start';
startTimeFormControl: FormControl;
endTimeFormControl: FormControl;
private _dateFormat: string;
private _onChange: (value: any) => void;
private _onTouched: (value: any) => void;
private _programmaticChange!: boolean;
private _range: { start: Moment | null; end: Moment | null } = {
start: null,
end : null
};
private _timeFormat: string;
private _timeRange: boolean;
private readonly _timeRegExp: RegExp = new RegExp('^(0[0-9]|1[0-9]|2[0-4]|[0-9]):([0-5][0-9])(A|(?:AM)|P|(?:PM))?$', 'i');
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
* Constructor
*/
constructor(
private _changeDetectorRef: ChangeDetectorRef,
private _elementRef: ElementRef,
private _overlay: Overlay,
private _renderer2: Renderer2,
private _viewContainerRef: ViewContainerRef
)
{
this._onChange = () => {
};
this._onTouched = () => {
};
this.dateFormat = 'DD/MM/YYYY';
this.timeFormat = '12';
// Initialize the component
this._init();
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Setter & getter for dateFormat input
*
* @param value
*/
@Input()
set dateFormat(value: string)
{
// Return if the values are the same
if ( this._dateFormat === value )
{
return;
}
// Store the value
this._dateFormat = value;
}
get dateFormat(): string
{
return this._dateFormat;
}
/**
* Setter & getter for timeFormat input
*
* @param value
*/
@Input()
set timeFormat(value: string)
{
// Return if the values are the same
if ( this._timeFormat === value )
{
return;
}
// Set format based on the time format input
this._timeFormat = value === '12' ? 'hh:mmA' : 'HH:mm';
}
get timeFormat(): string
{
return this._timeFormat;
}
/**
* Setter & getter for timeRange input
*
* @param value
*/
@Input()
set timeRange(value: boolean)
{
// Return if the values are the same
if ( this._timeRange === value )
{
return;
}
// Store the value
this._timeRange = value;
// If the time range turned off...
if ( !value )
{
this.range = {
start: this._range.start.clone().startOf('day'),
end : this._range.end.clone().endOf('day')
};
}
}
get timeRange(): boolean
{
return this._timeRange;
}
/**
* Setter & getter for range input
*
* @param value
*/
@Input()
set range(value)
{
if ( !value )
{
return;
}
// Check if the value is an object and has 'start' and 'end' values
if ( !value.start || !value.end )
{
console.error('Range input must have "start" and "end" properties!');
return;
}
// Check if we are setting an individual date or both of them
const whichDate = value.whichDate || null;
// Get the start and end dates as moment
const start = moment(value.start);
const end = moment(value.end);
// If we are only setting the start date...
if ( whichDate === 'start' )
{
// Set the start date
this._range.start = start.clone();
// If the selected start date is after the end date...
if ( this._range.start.isAfter(this._range.end) )
{
// Set the end date to the start date but keep the end date's time
const endDate = start.clone().hours(this._range.end.hours()).minutes(this._range.end.minutes()).seconds(this._range.end.seconds());
// Test this new end date to see if it's ahead of the start date
if ( this._range.start.isBefore(endDate) )
{
// If it's, set the new end date
this._range.end = endDate;
}
else
{
// Otherwise, set the end date same as the start date
this._range.end = start.clone();
}
}
}
// If we are only setting the end date...
if ( whichDate === 'end' )
{
// Set the end date
this._range.end = end.clone();
// If the selected end date is before the start date...
if ( this._range.start.isAfter(this._range.end) )
{
// Set the start date to the end date but keep the start date's time
const startDate = end.clone().hours(this._range.start.hours()).minutes(this._range.start.minutes()).seconds(this._range.start.seconds());
// Test this new end date to see if it's ahead of the start date
if ( this._range.end.isAfter(startDate) )
{
// If it's, set the new start date
this._range.start = startDate;
}
else
{
// Otherwise, set the start date same as the end date
this._range.start = end.clone();
}
}
}
// If we are setting both dates...
if ( !whichDate )
{
// Set the start date
this._range.start = start.clone();
// If the start date is before the end date, set the end date as normal.
// If the start date is after the end date, set the end date same as the start date.
this._range.end = start.isBefore(end) ? end.clone() : start.clone();
}
// Prepare another range object that holds the ISO formatted range dates
const range = {
start: this._range.start.clone().toISOString(),
end : this._range.end.clone().toISOString()
};
// Emit the range changed event with the range
this.rangeChanged.emit(range);
// Update the model with the range if the change was not a programmatic change
// Because programmatic changes trigger writeValue which triggers onChange and onTouched
// internally causing them to trigger twice which breaks the form's pristine and touched
// statuses.
if ( !this._programmaticChange )
{
this._onTouched(range);
this._onChange(range);
}
// Set the active dates
this.activeDates = {
month1: this._range.start.clone(),
month2: this._range.start.clone().add(1, 'month')
};
// Set the time form controls
this.startTimeFormControl.setValue(this._range.start.clone().format(this._timeFormat).toString());
this.endTimeFormControl.setValue(this._range.end.clone().format(this._timeFormat).toString());
// Run ngAfterContentInit on month views to trigger
// re-render on month views if they are available
if ( this._matMonthView1 && this._matMonthView2 )
{
this._matMonthView1.ngAfterContentInit();
this._matMonthView2.ngAfterContentInit();
}
// Reset the programmatic change status
this._programmaticChange = false;
}
get range(): any
{
// Clone the range start and end
const start = this._range.start.clone();
const end = this._range.end.clone();
// Build and return the range object
return {
startDate: start.clone().format(this.dateFormat),
startTime: this.timeRange ? start.clone().format(this.timeFormat) : null,
endDate : end.clone().format(this.dateFormat),
endTime : this.timeRange ? end.clone().format(this.timeFormat) : null
};
}
// -----------------------------------------------------------------------------------------------------
// @ Control Value Accessor
// -----------------------------------------------------------------------------------------------------
/**
* Update the form model on change
*
* @param fn
*/
registerOnChange(fn: any): void
{
this._onChange = fn;
}
/**
* Update the form model on blur
*
* @param fn
*/
registerOnTouched(fn: any): void
{
this._onTouched = fn;
}
/**
* Write to view from model when the form model changes programmatically
*
* @param range
*/
writeValue(range: { start: string; end: string }): void
{
// Set this change as a programmatic one
this._programmaticChange = true;
// Set the range
this.range = range;
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
// @ TODO: Workaround until "angular/issues/20007" resolved
this.writeValue = () => {
};
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Open the picker panel
*/
openPickerPanel(): void
{
// Create the overlay
const overlayRef = this._overlay.create({
panelClass : 'fuse-date-range-panel',
backdropClass : '',
hasBackdrop : true,
scrollStrategy : this._overlay.scrollStrategies.reposition(),
positionStrategy: this._overlay.position()
.flexibleConnectedTo(this._pickerPanelOrigin)
.withPositions([
{
originX : 'start',
originY : 'bottom',
overlayX: 'start',
overlayY: 'top',
offsetY : 8
},
{
originX : 'start',
originY : 'top',
overlayX: 'start',
overlayY: 'bottom',
offsetY : -8
}
])
});
// Create a portal from the template
const templatePortal = new TemplatePortal(this._pickerPanel, this._viewContainerRef);
// On backdrop click
overlayRef.backdropClick().subscribe(() => {
// If template portal exists and attached...
if ( templatePortal && templatePortal.isAttached )
{
// Detach it
templatePortal.detach();
}
// If overlay exists and attached...
if ( overlayRef && overlayRef.hasAttached() )
{
// Detach it
overlayRef.detach();
overlayRef.dispose();
}
});
// Attach the portal to the overlay
overlayRef.attach(templatePortal);
}
/**
* Get month label
*
* @param month
*/
getMonthLabel(month: number): string
{
if ( month === 1 )
{
return this.activeDates.month1.clone().format('MMMM Y');
}
return this.activeDates.month2.clone().format('MMMM Y');
}
/**
* Date class function to add/remove class names to calendar days
*/
dateClass(): any
{
return (date: Moment): MatCalendarCellCssClasses => {
// If the date is both start and end date...
if ( date.isSame(this._range.start, 'day') && date.isSame(this._range.end, 'day') )
{
return ['fuse-date-range', 'fuse-date-range-start', 'fuse-date-range-end'];
}
// If the date is the start date...
if ( date.isSame(this._range.start, 'day') )
{
return ['fuse-date-range', 'fuse-date-range-start'];
}
// If the date is the end date...
if ( date.isSame(this._range.end, 'day') )
{
return ['fuse-date-range', 'fuse-date-range-end'];
}
// If the date is in between start and end dates...
if ( date.isBetween(this._range.start, this._range.end, 'day') )
{
return ['fuse-date-range', 'fuse-date-range-mid'];
}
return undefined;
};
}
/**
* Date filter to enable/disable calendar days
*/
dateFilter(): any
{
// If we are selecting the end date, disable all the dates that comes before the start date
return (date: Moment): boolean => !(this.setWhichDate === 'end' && date.isBefore(this._range.start, 'day'));
}
/**
* On selected date change
*
* @param date
*/
onSelectedDateChange(date: Moment): void
{
// Create a new range object
const newRange = {
start : this._range.start.clone().toISOString(),
end : this._range.end.clone().toISOString(),
whichDate: null
};
// Replace either the start or the end date with the new one
// depending on which date we are setting
if ( this.setWhichDate === 'start' )
{
newRange.start = moment(newRange.start).year(date.year()).month(date.month()).date(date.date()).toISOString();
}
else
{
newRange.end = moment(newRange.end).year(date.year()).month(date.month()).date(date.date()).toISOString();
}
// Append the which date to the new range object
newRange.whichDate = this.setWhichDate;
// Switch which date to set on the next run
this.setWhichDate = this.setWhichDate === 'start' ? 'end' : 'start';
// Set the range
this.range = newRange;
}
/**
* Go to previous month on both views
*/
prev(): void
{
this.activeDates.month1 = moment(this.activeDates.month1).subtract(1, 'month');
this.activeDates.month2 = moment(this.activeDates.month2).subtract(1, 'month');
}
/**
* Go to next month on both views
*/
next(): void
{
this.activeDates.month1 = moment(this.activeDates.month1).add(1, 'month');
this.activeDates.month2 = moment(this.activeDates.month2).add(1, 'month');
}
/**
* Update the start time
*
* @param event
*/
updateStartTime(event): void
{
// Parse the time
const parsedTime = this._parseTime(event.target.value);
// Go back to the previous value if the form control is not valid
if ( this.startTimeFormControl.invalid )
{
// Override the time
const time = this._range.start.clone().format(this._timeFormat);
// Set the time
this.startTimeFormControl.setValue(time);
// Do not update the range
return;
}
// Append the new time to the start date
const startDate = this._range.start.clone().hours(parsedTime.hours()).minutes(parsedTime.minutes());
// If the new start date is after the current end date,
// use the end date's time and set the start date again
if ( startDate.isAfter(this._range.end) )
{
const endDateHours = this._range.end.hours();
const endDateMinutes = this._range.end.minutes();
// Set the start date
startDate.hours(endDateHours).minutes(endDateMinutes);
}
// If everything is okay, set the new date
this.range = {
start : startDate.toISOString(),
end : this._range.end.clone().toISOString(),
whichDate: 'start'
};
}
/**
* Update the end time
*
* @param event
*/
updateEndTime(event): void
{
// Parse the time
const parsedTime = this._parseTime(event.target.value);
// Go back to the previous value if the form control is not valid
if ( this.endTimeFormControl.invalid )
{
// Override the time
const time = this._range.end.clone().format(this._timeFormat);
// Set the time
this.endTimeFormControl.setValue(time);
// Do not update the range
return;
}
// Append the new time to the end date
const endDate = this._range.end.clone().hours(parsedTime.hours()).minutes(parsedTime.minutes());
// If the new end date is before the current start date,
// use the start date's time and set the end date again
if ( endDate.isBefore(this._range.start) )
{
const startDateHours = this._range.start.hours();
const startDateMinutes = this._range.start.minutes();
// Set the end date
endDate.hours(startDateHours).minutes(startDateMinutes);
}
// If everything is okay, set the new date
this.range = {
start : this._range.start.clone().toISOString(),
end : endDate.toISOString(),
whichDate: 'end'
};
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Initialize
*
* @private
*/
private _init(): void
{
// Start and end time form controls
this.startTimeFormControl = new FormControl('', [Validators.pattern(this._timeRegExp)]);
this.endTimeFormControl = new FormControl('', [Validators.pattern(this._timeRegExp)]);
// Set the default range
this._programmaticChange = true;
this.range = {
start: moment().startOf('day').toISOString(),
end : moment().add(1, 'day').endOf('day').toISOString()
};
// Set the default time range
this._programmaticChange = true;
this.timeRange = true;
}
/**
* Parse the time from the inputs
*
* @param value
* @private
*/
private _parseTime(value: string): Moment
{
// Parse the time using the time regexp
const timeArr = value.split(this._timeRegExp).filter(part => part !== '');
// Get the meridiem
const meridiem = timeArr[2] || null;
// If meridiem exists...
if ( meridiem )
{
// Create a moment using 12-hours format and return it
return moment(value, 'hh:mmA').seconds(0);
}
// If meridiem doesn't exist, create a moment using 24-hours format and return in
return moment(value, 'HH:mm').seconds(0);
}
}

View File

@@ -0,0 +1,32 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ReactiveFormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatMomentDateModule } from '@angular/material-moment-adapter';
import { FuseDateRangeComponent } from '@fuse/components/date-range/date-range.component';
@NgModule({
declarations: [
FuseDateRangeComponent
],
imports : [
CommonModule,
ReactiveFormsModule,
MatButtonModule,
MatDatepickerModule,
MatFormFieldModule,
MatInputModule,
MatIconModule,
MatMomentDateModule
],
exports : [
FuseDateRangeComponent
]
})
export class FuseDateRangeModule
{
}

View File

@@ -0,0 +1 @@
export * from '@fuse/components/date-range/public-api';

View File

@@ -0,0 +1,2 @@
export * from '@fuse/components/date-range/date-range.component';
export * from '@fuse/components/date-range/date-range.module';

View File

@@ -116,7 +116,7 @@ fuse-drawer {
left: 0; left: 0;
right: 0; right: 0;
z-index: 299; z-index: 299;
opacity: 1; opacity: 0;
background-color: rgba(0, 0, 0, 0.6); background-color: rgba(0, 0, 0, 0.6);
/* Fixed mode */ /* Fixed mode */

View File

@@ -211,12 +211,6 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
*/ */
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Finish the animation
if ( this._player )
{
this._player.finish();
}
// Deregister the drawer from the registry // Deregister the drawer from the registry
this._fuseDrawerService.deregisterComponent(this.name); this._fuseDrawerService.deregisterComponent(this.name);
} }
@@ -344,18 +338,9 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
// Create the enter animation and attach it to the player // Create the enter animation and attach it to the player
this._player = this._animationBuilder.build([ this._player = this._animationBuilder.build([
style({opacity: 0}),
animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({opacity: 1})) animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({opacity: 1}))
]).create(this._overlay); ]).create(this._overlay);
// Once the animation is done...
this._player.onDone(() => {
// Destroy the player
this._player.destroy();
this._player = null;
});
// Play the animation // Play the animation
this._player.play(); this._player.play();
@@ -388,10 +373,6 @@ export class FuseDrawerComponent implements OnChanges, OnInit, OnDestroy
// Once the animation is done... // Once the animation is done...
this._player.onDone(() => { this._player.onDone(() => {
// Destroy the player
this._player.destroy();
this._player = null;
// If the backdrop still exists... // If the backdrop still exists...
if ( this._overlay ) if ( this._overlay )
{ {

View File

@@ -1,12 +1,7 @@
<!-- Button --> <!-- Button -->
<button <button
mat-icon-button mat-icon-button
[matTooltip]="tooltip || 'Toggle Fullscreen'" [matTooltip]="'Toggle Fullscreen'"
(click)="toggleFullscreen()"> (click)="toggleFullscreen()">
<ng-container [ngTemplateOutlet]="iconTpl || defaultIconTpl"></ng-container>
</button>
<!-- Default icon -->
<ng-template #defaultIconTpl>
<mat-icon [svgIcon]="'heroicons_outline:arrows-expand'"></mat-icon> <mat-icon [svgIcon]="'heroicons_outline:arrows-expand'"></mat-icon>
</ng-template> </button>

View File

@@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, Inject, Input, OnInit, TemplateRef, ViewEncapsulation } from '@angular/core'; import { ChangeDetectionStrategy, Component, Inject, OnInit, ViewEncapsulation } from '@angular/core';
import { DOCUMENT } from '@angular/common'; import { DOCUMENT } from '@angular/common';
import { FSDocument, FSDocumentElement } from '@fuse/components/fullscreen/fullscreen.types'; import { FSDocument, FSDocumentElement } from '@fuse/components/fullscreen/fullscreen.types';
@@ -11,8 +11,6 @@ import { FSDocument, FSDocumentElement } from '@fuse/components/fullscreen/fulls
}) })
export class FuseFullscreenComponent implements OnInit export class FuseFullscreenComponent implements OnInit
{ {
@Input() iconTpl: TemplateRef<any>;
@Input() tooltip: string;
private _fsDoc: FSDocument; private _fsDoc: FSDocument;
private _fsDocEl: FSDocumentElement; private _fsDocEl: FSDocumentElement;
private _isFullscreen: boolean = false; private _isFullscreen: boolean = false;

View File

@@ -3,7 +3,6 @@ import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatTooltipModule } from '@angular/material/tooltip'; import { MatTooltipModule } from '@angular/material/tooltip';
import { FuseFullscreenComponent } from '@fuse/components/fullscreen/fullscreen.component'; import { FuseFullscreenComponent } from '@fuse/components/fullscreen/fullscreen.component';
import { CommonModule } from '@angular/common';
@NgModule({ @NgModule({
declarations: [ declarations: [
@@ -12,8 +11,7 @@ import { CommonModule } from '@angular/common';
imports : [ imports : [
MatButtonModule, MatButtonModule,
MatIconModule, MatIconModule,
MatTooltipModule, MatTooltipModule
CommonModule
], ],
exports : [ exports : [
FuseFullscreenComponent FuseFullscreenComponent

View File

@@ -1,5 +1,5 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import hljs from 'highlight.js'; import * as hljs from 'highlight.js';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'

View File

@@ -1 +0,0 @@
export * from '@fuse/components/loading-bar/public-api';

View File

@@ -1,5 +0,0 @@
<ng-container *ngIf="show">
<mat-progress-bar
[mode]="mode"
[value]="progress"></mat-progress-bar>
</ng-container>

View File

@@ -1,7 +0,0 @@
fuse-loading-bar {
position: fixed;
top: 0;
z-index: 999;
width: 100%;
height: 6px;
}

View File

@@ -1,82 +0,0 @@
import { Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { Subject, takeUntil } from 'rxjs';
import { FuseLoadingService } from '@fuse/services/loading';
@Component({
selector : 'fuse-loading-bar',
templateUrl : './loading-bar.component.html',
styleUrls : ['./loading-bar.component.scss'],
encapsulation: ViewEncapsulation.None,
exportAs : 'fuseLoadingBar'
})
export class FuseLoadingBarComponent implements OnChanges, OnInit, OnDestroy
{
@Input() autoMode: boolean = true;
mode: 'determinate' | 'indeterminate';
progress: number = 0;
show: boolean = false;
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
* Constructor
*/
constructor(private _fuseLoadingService: FuseLoadingService)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On changes
*
* @param changes
*/
ngOnChanges(changes: SimpleChanges): void
{
// Auto mode
if ( 'autoMode' in changes )
{
// Set the auto mode in the service
this._fuseLoadingService.setAutoMode(coerceBooleanProperty(changes.autoMode.currentValue));
}
}
/**
* On init
*/
ngOnInit(): void
{
// Subscribe to the service
this._fuseLoadingService.mode$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((value) => {
this.mode = value;
});
this._fuseLoadingService.progress$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((value) => {
this.progress = value;
});
this._fuseLoadingService.show$
.pipe(takeUntil(this._unsubscribeAll))
.subscribe((value) => {
this.show = value;
});
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next(null);
this._unsubscribeAll.complete();
}
}

View File

@@ -1,20 +0,0 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { FuseLoadingBarComponent } from '@fuse/components/loading-bar/loading-bar.component';
@NgModule({
declarations: [
FuseLoadingBarComponent
],
imports : [
CommonModule,
MatProgressBarModule
],
exports : [
FuseLoadingBarComponent
]
})
export class FuseLoadingBarModule
{
}

View File

@@ -1,2 +0,0 @@
export * from '@fuse/components/loading-bar/loading-bar.component';
export * from '@fuse/components/loading-bar/loading-bar.module';

View File

@@ -1 +1 @@
export * from '@fuse/components/masonry/public-api'; export * from '@fuse/components/card/public-api';

View File

@@ -5,83 +5,69 @@
[ngClass]="item.classes?.wrapper"> [ngClass]="item.classes?.wrapper">
<!-- Item with an internal link --> <!-- Item with an internal link -->
<ng-container *ngIf="item.link && !item.externalLink && !item.function && !item.disabled"> <div
<div class="fuse-horizontal-navigation-item"
class="fuse-horizontal-navigation-item" *ngIf="item.link && !item.externalLink && !item.function && !item.disabled"
[ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}" [ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]" [routerLink]="[item.link]"
[routerLinkActive]="'fuse-horizontal-navigation-item-active'" [routerLinkActive]="'fuse-horizontal-navigation-item-active'"
[routerLinkActiveOptions]="isActiveMatchOptions" [routerLinkActiveOptions]="{exact: item.exactMatch || false}">
[matTooltip]="item.tooltip || ''"> <ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container> </div>
</div>
</ng-container>
<!-- Item with an external link --> <!-- Item with an external link -->
<ng-container *ngIf="item.link && item.externalLink && !item.function && !item.disabled"> <a
<a class="fuse-horizontal-navigation-item"
class="fuse-horizontal-navigation-item" *ngIf="item.link && item.externalLink && !item.function && !item.disabled"
[href]="item.link" [href]="item.link">
[target]="item.target || '_self'" <ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
[matTooltip]="item.tooltip || ''"> </a>
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
</ng-container>
<!-- Item with a function --> <!-- Item with a function -->
<ng-container *ngIf="!item.link && item.function && !item.disabled"> <div
<div class="fuse-horizontal-navigation-item"
class="fuse-horizontal-navigation-item" *ngIf="!item.link && item.function && !item.disabled"
[ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}" [ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}"
[matTooltip]="item.tooltip || ''" (click)="item.function(item)">
(click)="item.function(item)"> <ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container> </div>
</div>
</ng-container>
<!-- Item with an internal link and function --> <!-- Item with an internal link and function -->
<ng-container *ngIf="item.link && !item.externalLink && item.function && !item.disabled"> <div
<div class="fuse-horizontal-navigation-item"
class="fuse-horizontal-navigation-item" *ngIf="item.link && !item.externalLink && item.function && !item.disabled"
[ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}" [ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]" [routerLink]="[item.link]"
[routerLinkActive]="'fuse-horizontal-navigation-item-active'" [routerLinkActive]="'fuse-horizontal-navigation-item-active'"
[routerLinkActiveOptions]="isActiveMatchOptions" [routerLinkActiveOptions]="{exact: item.exactMatch || false}"
[matTooltip]="item.tooltip || ''" (click)="item.function(item)">
(click)="item.function(item)"> <ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container> </div>
</div>
</ng-container>
<!-- Item with an external link and function --> <!-- Item with an external link and function -->
<ng-container *ngIf="item.link && item.externalLink && item.function && !item.disabled"> <a
<a class="fuse-horizontal-navigation-item"
class="fuse-horizontal-navigation-item" *ngIf="item.link && item.externalLink && item.function && !item.disabled"
[href]="item.link" [href]="item.link"
[target]="item.target || '_self'" (click)="item.function(item)"
[matTooltip]="item.tooltip || ''" mat-menu-item>
(click)="item.function(item)" <ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
mat-menu-item> </a>
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
</ng-container>
<!-- Item with a no link and no function --> <!-- Item with a no link and no function -->
<ng-container *ngIf="!item.link && !item.function && !item.disabled"> <div
<div class="fuse-horizontal-navigation-item"
class="fuse-horizontal-navigation-item" *ngIf="!item.link && !item.function && !item.disabled"
[ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}" [ngClass]="{'fuse-horizontal-navigation-item-active-forced': item.active}">
[matTooltip]="item.tooltip || ''"> <ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container> </div>
</div>
</ng-container>
<!-- Item is disabled --> <!-- Item is disabled -->
<ng-container *ngIf="item.disabled"> <div
<div class="fuse-horizontal-navigation-item fuse-horizontal-navigation-item-disabled"> class="fuse-horizontal-navigation-item fuse-horizontal-navigation-item-disabled"
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container> *ngIf="item.disabled">
</div> <ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</ng-container> </div>
</div> </div>
@@ -89,12 +75,11 @@
<ng-template #itemTemplate> <ng-template #itemTemplate>
<!-- Icon --> <!-- Icon -->
<ng-container *ngIf="item.icon"> <mat-icon
<mat-icon class="fuse-horizontal-navigation-item-icon"
class="fuse-horizontal-navigation-item-icon" [ngClass]="item.classes?.icon"
[ngClass]="item.classes?.icon" *ngIf="item.icon"
[svgIcon]="item.icon"></mat-icon> [svgIcon]="item.icon"></mat-icon>
</ng-container>
<!-- Title & Subtitle --> <!-- Title & Subtitle -->
<div class="fuse-horizontal-navigation-item-title-wrapper"> <div class="fuse-horizontal-navigation-item-title-wrapper">
@@ -103,24 +88,24 @@
{{item.title}} {{item.title}}
</span> </span>
</div> </div>
<ng-container *ngIf="item.subtitle"> <div
<div class="fuse-horizontal-navigation-item-subtitle text-hint"> class="fuse-horizontal-navigation-item-subtitle text-hint"
<span [ngClass]="item.classes?.subtitle"> *ngIf="item.subtitle">
{{item.subtitle}} <span [ngClass]="item.classes?.subtitle">
</span> {{item.subtitle}}
</div> </span>
</ng-container> </div>
</div> </div>
<!-- Badge --> <!-- Badge -->
<ng-container *ngIf="item.badge"> <div
<div class="fuse-horizontal-navigation-item-badge"> class="fuse-horizontal-navigation-item-badge"
<div *ngIf="item.badge">
class="fuse-horizontal-navigation-item-badge-content" <div
[ngClass]="item.badge.classes"> class="fuse-horizontal-navigation-item-badge-content"
{{item.badge.title}} [ngClass]="item.badge.classes">
</div> {{item.badge.title}}
</div> </div>
</ng-container> </div>
</ng-template> </ng-template>

View File

@@ -1,14 +1,14 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
import { IsActiveMatchOptions } from '@angular/router'; import { Subject } from 'rxjs';
import { Subject, takeUntil } from 'rxjs'; import { takeUntil } from 'rxjs/operators';
import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component'; import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
import { FuseUtilsService } from '@fuse/services/utils/utils.service';
@Component({ @Component({
selector : 'fuse-horizontal-navigation-basic-item', selector : 'fuse-horizontal-navigation-basic-item',
templateUrl : './basic.component.html', templateUrl : './basic.component.html',
styles : [],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class FuseHorizontalNavigationBasicItemComponent implements OnInit, OnDestroy export class FuseHorizontalNavigationBasicItemComponent implements OnInit, OnDestroy
@@ -16,7 +16,6 @@ export class FuseHorizontalNavigationBasicItemComponent implements OnInit, OnDes
@Input() item: FuseNavigationItem; @Input() item: FuseNavigationItem;
@Input() name: string; @Input() name: string;
isActiveMatchOptions: IsActiveMatchOptions;
private _fuseHorizontalNavigationComponent: FuseHorizontalNavigationComponent; private _fuseHorizontalNavigationComponent: FuseHorizontalNavigationComponent;
private _unsubscribeAll: Subject<any> = new Subject<any>(); private _unsubscribeAll: Subject<any> = new Subject<any>();
@@ -25,15 +24,9 @@ export class FuseHorizontalNavigationBasicItemComponent implements OnInit, OnDes
*/ */
constructor( constructor(
private _changeDetectorRef: ChangeDetectorRef, private _changeDetectorRef: ChangeDetectorRef,
private _fuseNavigationService: FuseNavigationService, private _fuseNavigationService: FuseNavigationService
private _fuseUtilsService: FuseUtilsService
) )
{ {
// Set the equivalent of {exact: false} as default for active match options.
// We are not assigning the item.isActiveMatchOptions directly to the
// [routerLinkActiveOptions] because if it's "undefined" initially, the router
// will throw an error and stop working.
this.isActiveMatchOptions = this._fuseUtilsService.subsetMatchOptions;
} }
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -45,20 +38,9 @@ export class FuseHorizontalNavigationBasicItemComponent implements OnInit, OnDes
*/ */
ngOnInit(): void ngOnInit(): void
{ {
// Set the "isActiveMatchOptions" either from item's
// "isActiveMatchOptions" or the equivalent form of
// item's "exactMatch" option
this.isActiveMatchOptions =
this.item.isActiveMatchOptions ?? this.item.exactMatch
? this._fuseUtilsService.exactMatchOptions
: this._fuseUtilsService.subsetMatchOptions;
// Get the parent navigation component // Get the parent navigation component
this._fuseHorizontalNavigationComponent = this._fuseNavigationService.getComponent(this.name); this._fuseHorizontalNavigationComponent = this._fuseNavigationService.getComponent(this.name);
// Mark for check
this._changeDetectorRef.markForCheck();
// Subscribe to onRefreshed on the navigation component // Subscribe to onRefreshed on the navigation component
this._fuseHorizontalNavigationComponent.onRefreshed.pipe( this._fuseHorizontalNavigationComponent.onRefreshed.pipe(
takeUntil(this._unsubscribeAll) takeUntil(this._unsubscribeAll)
@@ -75,7 +57,7 @@ export class FuseHorizontalNavigationBasicItemComponent implements OnInit, OnDes
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(null); this._unsubscribeAll.next();
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }
} }

View File

@@ -1,63 +1,59 @@
<ng-container *ngIf="!child"> <div
<div *ngIf="!child"
[ngClass]="{'fuse-horizontal-navigation-menu-active': trigger.menuOpen, [ngClass]="{'fuse-horizontal-navigation-menu-active': trigger.menuOpen,
'fuse-horizontal-navigation-menu-active-forced': item.active}" 'fuse-horizontal-navigation-menu-active-forced': item.active}"
[matMenuTriggerFor]="matMenu" [matMenuTriggerFor]="matMenu"
(onMenuOpen)="triggerChangeDetection()" (onMenuOpen)="triggerChangeDetection()"
(onMenuClose)="triggerChangeDetection()" (onMenuClose)="triggerChangeDetection()"
#trigger="matMenuTrigger"> #trigger="matMenuTrigger">
<ng-container *ngTemplateOutlet="itemTemplate; context: {$implicit: item}"></ng-container> <ng-container *ngTemplateOutlet="itemTemplate; context: {$implicit: item}"></ng-container>
</div> </div>
</ng-container>
<mat-menu <mat-menu
class="fuse-horizontal-navigation-menu-panel" class="fuse-horizontal-navigation-menu-panel"
[overlapTrigger]="false" [overlapTrigger]="false"
#matMenu="matMenu"> #matMenu="matMenu">
<ng-container *ngFor="let item of item.children; trackBy: trackByFn"> <ng-container *ngFor="let item of item.children">
<!-- Skip the hidden items --> <!-- Skip the hidden items -->
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden"> <ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Basic --> <!-- Basic -->
<ng-container *ngIf="item.type === 'basic'"> <div
<div class="fuse-horizontal-navigation-menu-item"
class="fuse-horizontal-navigation-menu-item" *ngIf="item.type === 'basic'"
[disabled]="item.disabled" [disabled]="item.disabled"
mat-menu-item> mat-menu-item>
<fuse-horizontal-navigation-basic-item <fuse-horizontal-navigation-basic-item
[item]="item" [item]="item"
[name]="name"></fuse-horizontal-navigation-basic-item> [name]="name"></fuse-horizontal-navigation-basic-item>
</div> </div>
</ng-container>
<!-- Branch: aside, collapsable, group --> <!-- Branch: aside, collapsable, group -->
<ng-container *ngIf="item.type === 'aside' || item.type === 'collapsable' || item.type === 'group'"> <div
<div class="fuse-horizontal-navigation-menu-item"
class="fuse-horizontal-navigation-menu-item" *ngIf="item.type === 'aside' || item.type === 'collapsable' || item.type === 'group'"
[disabled]="item.disabled" [disabled]="item.disabled"
[matMenuTriggerFor]="branch.matMenu" [matMenuTriggerFor]="branch.matMenu"
mat-menu-item> mat-menu-item>
<ng-container *ngTemplateOutlet="itemTemplate; context: {$implicit: item}"></ng-container> <ng-container *ngTemplateOutlet="itemTemplate; context: {$implicit: item}"></ng-container>
<fuse-horizontal-navigation-branch-item <fuse-horizontal-navigation-branch-item
[child]="true" [child]="true"
[item]="item" [item]="item"
[name]="name" [name]="name"
#branch></fuse-horizontal-navigation-branch-item> #branch></fuse-horizontal-navigation-branch-item>
</div> </div>
</ng-container>
<!-- Divider --> <!-- Divider -->
<ng-container *ngIf="item.type === 'divider'"> <div
<div class="fuse-horizontal-navigation-menu-item"
class="fuse-horizontal-navigation-menu-item" *ngIf="item.type === 'divider'"
mat-menu-item> mat-menu-item>
<fuse-horizontal-navigation-divider-item <fuse-horizontal-navigation-divider-item
[item]="item" [item]="item"
[name]="name"></fuse-horizontal-navigation-divider-item> [name]="name"></fuse-horizontal-navigation-divider-item>
</div> </div>
</ng-container>
</ng-container> </ng-container>
@@ -78,16 +74,14 @@
<div <div
class="fuse-horizontal-navigation-item" class="fuse-horizontal-navigation-item"
[ngClass]="{'fuse-horizontal-navigation-item-disabled': item.disabled, [ngClass]="{'fuse-horizontal-navigation-item-disabled': item.disabled,
'fuse-horizontal-navigation-item-active-forced': item.active}" 'fuse-horizontal-navigation-item-active-forced': item.active}">
[matTooltip]="item.tooltip || ''">
<!-- Icon --> <!-- Icon -->
<ng-container *ngIf="item.icon"> <mat-icon
<mat-icon class="fuse-horizontal-navigation-item-icon"
class="fuse-horizontal-navigation-item-icon" [ngClass]="item.classes?.icon"
[ngClass]="item.classes?.icon" *ngIf="item.icon"
[svgIcon]="item.icon"></mat-icon> [svgIcon]="item.icon"></mat-icon>
</ng-container>
<!-- Title & Subtitle --> <!-- Title & Subtitle -->
<div class="fuse-horizontal-navigation-item-title-wrapper"> <div class="fuse-horizontal-navigation-item-title-wrapper">
@@ -96,25 +90,25 @@
{{item.title}} {{item.title}}
</span> </span>
</div> </div>
<ng-container *ngIf="item.subtitle"> <div
<div class="fuse-horizontal-navigation-item-subtitle text-hint"> class="fuse-horizontal-navigation-item-subtitle text-hint"
<span [ngClass]="item.classes?.subtitle"> *ngIf="item.subtitle">
{{item.subtitle}} <span [ngClass]="item.classes?.subtitle">
</span> {{item.subtitle}}
</div> </span>
</ng-container> </div>
</div> </div>
<!-- Badge --> <!-- Badge -->
<ng-container *ngIf="item.badge"> <div
<div class="fuse-horizontal-navigation-item-badge"> class="fuse-horizontal-navigation-item-badge"
<div *ngIf="item.badge">
class="fuse-horizontal-navigation-item-badge-content" <div
[ngClass]="item.badge.classes"> class="fuse-horizontal-navigation-item-badge-content"
{{item.badge.title}} [ngClass]="item.badge.classes">
</div> {{item.badge.title}}
</div> </div>
</ng-container> </div>
</div> </div>
</div> </div>

View File

@@ -1,7 +1,8 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { BooleanInput } from '@angular/cdk/coercion'; import { BooleanInput } from '@angular/cdk/coercion';
import { MatMenu } from '@angular/material/menu'; import { MatMenu } from '@angular/material/menu';
import { Subject, takeUntil } from 'rxjs'; import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component'; import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
@@ -9,6 +10,7 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
@Component({ @Component({
selector : 'fuse-horizontal-navigation-branch-item', selector : 'fuse-horizontal-navigation-branch-item',
templateUrl : './branch.component.html', templateUrl : './branch.component.html',
styles : [],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class FuseHorizontalNavigationBranchItemComponent implements OnInit, OnDestroy export class FuseHorizontalNavigationBranchItemComponent implements OnInit, OnDestroy
@@ -63,7 +65,7 @@ export class FuseHorizontalNavigationBranchItemComponent implements OnInit, OnDe
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(null); this._unsubscribeAll.next();
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }
@@ -79,15 +81,4 @@ export class FuseHorizontalNavigationBranchItemComponent implements OnInit, OnDe
// Mark for check // Mark for check
this._changeDetectorRef.markForCheck(); this._changeDetectorRef.markForCheck();
} }
/**
* Track by function for ngFor loops
*
* @param index
* @param item
*/
trackByFn(index: number, item: any): any
{
return item.id || index;
}
} }

View File

@@ -1,5 +1,6 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
import { Subject, takeUntil } from 'rxjs'; import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component'; import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
@@ -7,6 +8,7 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
@Component({ @Component({
selector : 'fuse-horizontal-navigation-divider-item', selector : 'fuse-horizontal-navigation-divider-item',
templateUrl : './divider.component.html', templateUrl : './divider.component.html',
styles : [],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class FuseHorizontalNavigationDividerItemComponent implements OnInit, OnDestroy export class FuseHorizontalNavigationDividerItemComponent implements OnInit, OnDestroy
@@ -55,7 +57,7 @@ export class FuseHorizontalNavigationDividerItemComponent implements OnInit, OnD
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(null); this._unsubscribeAll.next();
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }
} }

View File

@@ -1,5 +1,6 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
import { Subject, takeUntil } from 'rxjs'; import { takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component'; import { FuseHorizontalNavigationComponent } from '@fuse/components/navigation/horizontal/horizontal.component';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
@@ -7,6 +8,7 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
@Component({ @Component({
selector : 'fuse-horizontal-navigation-spacer-item', selector : 'fuse-horizontal-navigation-spacer-item',
templateUrl : './spacer.component.html', templateUrl : './spacer.component.html',
styles : [],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class FuseHorizontalNavigationSpacerItemComponent implements OnInit, OnDestroy export class FuseHorizontalNavigationSpacerItemComponent implements OnInit, OnDestroy
@@ -55,7 +57,7 @@ export class FuseHorizontalNavigationSpacerItemComponent implements OnInit, OnDe
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(null); this._unsubscribeAll.next();
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }
} }

View File

@@ -1,33 +1,30 @@
<div class="fuse-horizontal-navigation-wrapper"> <div class="fuse-horizontal-navigation-wrapper">
<ng-container *ngFor="let item of navigation; trackBy: trackByFn"> <ng-container *ngFor="let item of navigation">
<!-- Skip the hidden items --> <!-- Skip the hidden items -->
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden"> <ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Basic --> <!-- Basic -->
<ng-container *ngIf="item.type === 'basic'"> <fuse-horizontal-navigation-basic-item
<fuse-horizontal-navigation-basic-item class="fuse-horizontal-navigation-menu-item"
class="fuse-horizontal-navigation-menu-item" *ngIf="item.type === 'basic'"
[item]="item" [item]="item"
[name]="name"></fuse-horizontal-navigation-basic-item> [name]="name"></fuse-horizontal-navigation-basic-item>
</ng-container>
<!-- Branch: aside, collapsable, group --> <!-- Branch: aside, collapsable, group -->
<ng-container *ngIf="item.type === 'aside' || item.type === 'collapsable' || item.type === 'group'"> <fuse-horizontal-navigation-branch-item
<fuse-horizontal-navigation-branch-item class="fuse-horizontal-navigation-menu-item"
class="fuse-horizontal-navigation-menu-item" *ngIf="item.type === 'aside' || item.type === 'collapsable' || item.type === 'group'"
[item]="item" [item]="item"
[name]="name"></fuse-horizontal-navigation-branch-item> [name]="name"></fuse-horizontal-navigation-branch-item>
</ng-container>
<!-- Spacer --> <!-- Spacer -->
<ng-container *ngIf="item.type === 'spacer'"> <fuse-horizontal-navigation-spacer-item
<fuse-horizontal-navigation-spacer-item class="fuse-horizontal-navigation-menu-item"
class="fuse-horizontal-navigation-menu-item" *ngIf="item.type === 'spacer'"
[item]="item" [item]="item"
[name]="name"></fuse-horizontal-navigation-spacer-item> [name]="name"></fuse-horizontal-navigation-spacer-item>
</ng-container>
</ng-container> </ng-container>

View File

@@ -76,7 +76,7 @@ export class FuseHorizontalNavigationComponent implements OnChanges, OnInit, OnD
this._fuseNavigationService.deregisterComponent(this.name); this._fuseNavigationService.deregisterComponent(this.name);
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(null); this._unsubscribeAll.next();
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }

View File

@@ -46,7 +46,7 @@ export class FuseNavigationService
* *
* @param name * @param name
*/ */
getComponent<T>(name: string): T getComponent(name: string): any
{ {
return this._componentRegistry.get(name); return this._componentRegistry.get(name);
} }

View File

@@ -1,5 +1,3 @@
import { IsActiveMatchOptions } from '@angular/router';
export interface FuseNavigationItem export interface FuseNavigationItem
{ {
id?: string; id?: string;
@@ -15,17 +13,9 @@ export interface FuseNavigationItem
hidden?: (item: FuseNavigationItem) => boolean; hidden?: (item: FuseNavigationItem) => boolean;
active?: boolean; active?: boolean;
disabled?: boolean; disabled?: boolean;
tooltip?: string;
link?: string; link?: string;
externalLink?: boolean; externalLink?: boolean;
target?:
| '_blank'
| '_self'
| '_parent'
| '_top'
| string;
exactMatch?: boolean; exactMatch?: boolean;
isActiveMatchOptions?: IsActiveMatchOptions;
function?: (item: FuseNavigationItem) => void; function?: (item: FuseNavigationItem) => void;
classes?: { classes?: {
title?: string; title?: string;

View File

@@ -7,16 +7,14 @@
class="fuse-vertical-navigation-item" class="fuse-vertical-navigation-item"
[ngClass]="{'fuse-vertical-navigation-item-active': active, [ngClass]="{'fuse-vertical-navigation-item-active': active,
'fuse-vertical-navigation-item-disabled': item.disabled, 'fuse-vertical-navigation-item-disabled': item.disabled,
'fuse-vertical-navigation-item-active-forced': item.active}" 'fuse-vertical-navigation-item-active-forced': item.active}">
[matTooltip]="item.tooltip || ''">
<!-- Icon --> <!-- Icon -->
<ng-container *ngIf="item.icon"> <mat-icon
<mat-icon class="fuse-vertical-navigation-item-icon"
class="fuse-vertical-navigation-item-icon" [ngClass]="item.classes?.icon"
[ngClass]="item.classes?.icon" *ngIf="item.icon"
[svgIcon]="item.icon"></mat-icon> [svgIcon]="item.icon"></mat-icon>
</ng-container>
<!-- Title & Subtitle --> <!-- Title & Subtitle -->
<div class="fuse-vertical-navigation-item-title-wrapper"> <div class="fuse-vertical-navigation-item-title-wrapper">
@@ -25,25 +23,25 @@
{{item.title}} {{item.title}}
</span> </span>
</div> </div>
<ng-container *ngIf="item.subtitle"> <div
<div class="fuse-vertical-navigation-item-subtitle"> class="fuse-vertical-navigation-item-subtitle"
<span [ngClass]="item.classes?.subtitle"> *ngIf="item.subtitle">
{{item.subtitle}} <span [ngClass]="item.classes?.subtitle">
</span> {{item.subtitle}}
</div> </span>
</ng-container> </div>
</div> </div>
<!-- Badge --> <!-- Badge -->
<ng-container *ngIf="item.badge"> <div
<div class="fuse-vertical-navigation-item-badge"> class="fuse-vertical-navigation-item-badge"
<div *ngIf="item.badge">
class="fuse-vertical-navigation-item-badge-content" <div
[ngClass]="item.badge.classes"> class="fuse-vertical-navigation-item-badge-content"
{{item.badge.title}} [ngClass]="item.badge.classes">
</div> {{item.badge.title}}
</div> </div>
</ng-container> </div>
</div> </div>
@@ -59,40 +57,35 @@
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden"> <ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Basic --> <!-- Basic -->
<ng-container *ngIf="item.type === 'basic'"> <fuse-vertical-navigation-basic-item
<fuse-vertical-navigation-basic-item *ngIf="item.type === 'basic'"
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-basic-item> [name]="name"></fuse-vertical-navigation-basic-item>
</ng-container>
<!-- Collapsable --> <!-- Collapsable -->
<ng-container *ngIf="item.type === 'collapsable'"> <fuse-vertical-navigation-collapsable-item
<fuse-vertical-navigation-collapsable-item *ngIf="item.type === 'collapsable'"
[item]="item" [item]="item"
[name]="name" [name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item> [autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item>
</ng-container>
<!-- Divider --> <!-- Divider -->
<ng-container *ngIf="item.type === 'divider'"> <fuse-vertical-navigation-divider-item
<fuse-vertical-navigation-divider-item *ngIf="item.type === 'divider'"
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-divider-item> [name]="name"></fuse-vertical-navigation-divider-item>
</ng-container>
<!-- Group --> <!-- Group -->
<ng-container *ngIf="item.type === 'group'"> <fuse-vertical-navigation-group-item
<fuse-vertical-navigation-group-item *ngIf="item.type === 'group'"
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-group-item> [name]="name"></fuse-vertical-navigation-group-item>
</ng-container>
<!-- Spacer --> <!-- Spacer -->
<ng-container *ngIf="item.type === 'spacer'"> <fuse-vertical-navigation-spacer-item
<fuse-vertical-navigation-spacer-item *ngIf="item.type === 'spacer'"
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-spacer-item> [name]="name"></fuse-vertical-navigation-spacer-item>
</ng-container>
</ng-container> </ng-container>

View File

@@ -1,7 +1,8 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
import { NavigationEnd, Router } from '@angular/router'; import { NavigationEnd, Router } from '@angular/router';
import { BooleanInput } from '@angular/cdk/coercion'; import { BooleanInput } from '@angular/cdk/coercion';
import { filter, Subject, takeUntil } from 'rxjs'; import { Subject } from 'rxjs';
import { filter, takeUntil } from 'rxjs/operators';
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component'; import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
@@ -9,6 +10,7 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
@Component({ @Component({
selector : 'fuse-vertical-navigation-aside-item', selector : 'fuse-vertical-navigation-aside-item',
templateUrl : './aside.component.html', templateUrl : './aside.component.html',
styles : [],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class FuseVerticalNavigationAsideItemComponent implements OnChanges, OnInit, OnDestroy export class FuseVerticalNavigationAsideItemComponent implements OnChanges, OnInit, OnDestroy
@@ -97,7 +99,7 @@ export class FuseVerticalNavigationAsideItemComponent implements OnChanges, OnIn
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(null); this._unsubscribeAll.next();
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }

View File

@@ -5,84 +5,68 @@
[ngClass]="item.classes?.wrapper"> [ngClass]="item.classes?.wrapper">
<!-- Item with an internal link --> <!-- Item with an internal link -->
<ng-container *ngIf="item.link && !item.externalLink && !item.function && !item.disabled"> <a
<a class="fuse-vertical-navigation-item"
class="fuse-vertical-navigation-item" *ngIf="item.link && !item.externalLink && !item.function && !item.disabled"
[ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}" [ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]" [routerLink]="[item.link]"
[routerLinkActive]="'fuse-vertical-navigation-item-active'" [routerLinkActive]="'fuse-vertical-navigation-item-active'"
[routerLinkActiveOptions]="isActiveMatchOptions" [routerLinkActiveOptions]="{exact: item.exactMatch || false}">
[matTooltip]="item.tooltip || ''"> <ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container> </a>
</a>
</ng-container>
<!-- Item with an external link --> <!-- Item with an external link -->
<ng-container *ngIf="item.link && item.externalLink && !item.function && !item.disabled"> <a
<a class="fuse-vertical-navigation-item"
class="fuse-vertical-navigation-item" *ngIf="item.link && item.externalLink && !item.function && !item.disabled"
[href]="item.link" [href]="item.link">
[target]="item.target || '_self'" <ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
[matTooltip]="item.tooltip || ''"> </a>
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
</ng-container>
<!-- Item with a function --> <!-- Item with a function -->
<ng-container *ngIf="!item.link && item.function && !item.disabled"> <div
<div class="fuse-vertical-navigation-item"
class="fuse-vertical-navigation-item" *ngIf="!item.link && item.function && !item.disabled"
[ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}" [ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}"
[matTooltip]="item.tooltip || ''" (click)="item.function(item)">
(click)="item.function(item)"> <ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container> </div>
</div>
</ng-container>
<!-- Item with an internal link and function --> <!-- Item with an internal link and function -->
<ng-container *ngIf="item.link && !item.externalLink && item.function && !item.disabled"> <a
<a class="fuse-vertical-navigation-item"
class="fuse-vertical-navigation-item" *ngIf="item.link && !item.externalLink && item.function && !item.disabled"
[ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}" [ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}"
[routerLink]="[item.link]" [routerLink]="[item.link]"
[routerLinkActive]="'fuse-vertical-navigation-item-active'" [routerLinkActive]="'fuse-vertical-navigation-item-active'"
[routerLinkActiveOptions]="isActiveMatchOptions" [routerLinkActiveOptions]="{exact: item.exactMatch || false}"
[matTooltip]="item.tooltip || ''" (click)="item.function(item)">
(click)="item.function(item)"> <ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container> </a>
</a>
</ng-container>
<!-- Item with an external link and function --> <!-- Item with an external link and function -->
<ng-container *ngIf="item.link && item.externalLink && item.function && !item.disabled"> <a
<a class="fuse-vertical-navigation-item"
class="fuse-vertical-navigation-item" *ngIf="item.link && item.externalLink && item.function && !item.disabled"
[href]="item.link" [href]="item.link"
[target]="item.target || '_self'" (click)="item.function(item)">
[matTooltip]="item.tooltip || ''" <ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
(click)="item.function(item)"> </a>
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
</a>
</ng-container>
<!-- Item with a no link and no function --> <!-- Item with a no link and no function -->
<ng-container *ngIf="!item.link && !item.function && !item.disabled"> <div
<div class="fuse-vertical-navigation-item"
class="fuse-vertical-navigation-item" *ngIf="!item.link && !item.function && !item.disabled"
[ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}" [ngClass]="{'fuse-vertical-navigation-item-active-forced': item.active}">
[matTooltip]="item.tooltip || ''"> <ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container> </div>
</div>
</ng-container>
<!-- Item is disabled --> <!-- Item is disabled -->
<ng-container *ngIf="item.disabled"> <div
<div class="fuse-vertical-navigation-item fuse-vertical-navigation-item-disabled"
class="fuse-vertical-navigation-item fuse-vertical-navigation-item-disabled" *ngIf="item.disabled">
[matTooltip]="item.tooltip || ''"> <ng-container *ngTemplateOutlet="itemTemplate"></ng-container>
<ng-container *ngTemplateOutlet="itemTemplate"></ng-container> </div>
</div>
</ng-container>
</div> </div>
@@ -90,12 +74,11 @@
<ng-template #itemTemplate> <ng-template #itemTemplate>
<!-- Icon --> <!-- Icon -->
<ng-container *ngIf="item.icon"> <mat-icon
<mat-icon class="fuse-vertical-navigation-item-icon"
class="fuse-vertical-navigation-item-icon" [ngClass]="item.classes?.icon"
[ngClass]="item.classes?.icon" *ngIf="item.icon"
[svgIcon]="item.icon"></mat-icon> [svgIcon]="item.icon"></mat-icon>
</ng-container>
<!-- Title & Subtitle --> <!-- Title & Subtitle -->
<div class="fuse-vertical-navigation-item-title-wrapper"> <div class="fuse-vertical-navigation-item-title-wrapper">
@@ -104,24 +87,24 @@
{{item.title}} {{item.title}}
</span> </span>
</div> </div>
<ng-container *ngIf="item.subtitle"> <div
<div class="fuse-vertical-navigation-item-subtitle"> class="fuse-vertical-navigation-item-subtitle"
<span [ngClass]="item.classes?.subtitle"> *ngIf="item.subtitle">
{{item.subtitle}} <span [ngClass]="item.classes?.subtitle">
</span> {{item.subtitle}}
</div> </span>
</ng-container> </div>
</div> </div>
<!-- Badge --> <!-- Badge -->
<ng-container *ngIf="item.badge"> <div
<div class="fuse-vertical-navigation-item-badge"> class="fuse-vertical-navigation-item-badge"
<div *ngIf="item.badge">
class="fuse-vertical-navigation-item-badge-content" <div
[ngClass]="item.badge.classes"> class="fuse-vertical-navigation-item-badge-content"
{{item.badge.title}} [ngClass]="item.badge.classes">
</div> {{item.badge.title}}
</div> </div>
</ng-container> </div>
</ng-template> </ng-template>

View File

@@ -1,6 +1,6 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
import { IsActiveMatchOptions } from '@angular/router'; import { Subject } from 'rxjs';
import { Subject, takeUntil } from 'rxjs'; import { takeUntil } from 'rxjs/operators';
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component'; import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
@@ -9,6 +9,7 @@ import { FuseUtilsService } from '@fuse/services/utils/utils.service';
@Component({ @Component({
selector : 'fuse-vertical-navigation-basic-item', selector : 'fuse-vertical-navigation-basic-item',
templateUrl : './basic.component.html', templateUrl : './basic.component.html',
styles : [],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class FuseVerticalNavigationBasicItemComponent implements OnInit, OnDestroy export class FuseVerticalNavigationBasicItemComponent implements OnInit, OnDestroy
@@ -16,7 +17,6 @@ export class FuseVerticalNavigationBasicItemComponent implements OnInit, OnDestr
@Input() item: FuseNavigationItem; @Input() item: FuseNavigationItem;
@Input() name: string; @Input() name: string;
isActiveMatchOptions: IsActiveMatchOptions;
private _fuseVerticalNavigationComponent: FuseVerticalNavigationComponent; private _fuseVerticalNavigationComponent: FuseVerticalNavigationComponent;
private _unsubscribeAll: Subject<any> = new Subject<any>(); private _unsubscribeAll: Subject<any> = new Subject<any>();
@@ -29,11 +29,6 @@ export class FuseVerticalNavigationBasicItemComponent implements OnInit, OnDestr
private _fuseUtilsService: FuseUtilsService private _fuseUtilsService: FuseUtilsService
) )
{ {
// Set the equivalent of {exact: false} as default for active match options.
// We are not assigning the item.isActiveMatchOptions directly to the
// [routerLinkActiveOptions] because if it's "undefined" initially, the router
// will throw an error and stop working.
this.isActiveMatchOptions = this._fuseUtilsService.subsetMatchOptions;
} }
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
@@ -45,20 +40,9 @@ export class FuseVerticalNavigationBasicItemComponent implements OnInit, OnDestr
*/ */
ngOnInit(): void ngOnInit(): void
{ {
// Set the "isActiveMatchOptions" either from item's
// "isActiveMatchOptions" or the equivalent form of
// item's "exactMatch" option
this.isActiveMatchOptions =
this.item.isActiveMatchOptions ?? this.item.exactMatch
? this._fuseUtilsService.exactMatchOptions
: this._fuseUtilsService.subsetMatchOptions;
// Get the parent navigation component // Get the parent navigation component
this._fuseVerticalNavigationComponent = this._fuseNavigationService.getComponent(this.name); this._fuseVerticalNavigationComponent = this._fuseNavigationService.getComponent(this.name);
// Mark for check
this._changeDetectorRef.markForCheck();
// Subscribe to onRefreshed on the navigation component // Subscribe to onRefreshed on the navigation component
this._fuseVerticalNavigationComponent.onRefreshed.pipe( this._fuseVerticalNavigationComponent.onRefreshed.pipe(
takeUntil(this._unsubscribeAll) takeUntil(this._unsubscribeAll)
@@ -75,7 +59,7 @@ export class FuseVerticalNavigationBasicItemComponent implements OnInit, OnDestr
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(null); this._unsubscribeAll.next();
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }
} }

View File

@@ -6,16 +6,14 @@
<div <div
class="fuse-vertical-navigation-item" class="fuse-vertical-navigation-item"
[ngClass]="{'fuse-vertical-navigation-item-disabled': item.disabled}" [ngClass]="{'fuse-vertical-navigation-item-disabled': item.disabled}"
[matTooltip]="item.tooltip || ''"
(click)="toggleCollapsable()"> (click)="toggleCollapsable()">
<!-- Icon --> <!-- Icon -->
<ng-container *ngIf="item.icon"> <mat-icon
<mat-icon class="fuse-vertical-navigation-item-icon"
class="fuse-vertical-navigation-item-icon" [ngClass]="item.classes?.icon"
[ngClass]="item.classes?.icon" *ngIf="item.icon"
[svgIcon]="item.icon"></mat-icon> [svgIcon]="item.icon"></mat-icon>
</ng-container>
<!-- Title & Subtitle --> <!-- Title & Subtitle -->
<div class="fuse-vertical-navigation-item-title-wrapper"> <div class="fuse-vertical-navigation-item-title-wrapper">
@@ -24,25 +22,25 @@
{{item.title}} {{item.title}}
</span> </span>
</div> </div>
<ng-container *ngIf="item.subtitle"> <div
<div class="fuse-vertical-navigation-item-subtitle"> class="fuse-vertical-navigation-item-subtitle"
<span [ngClass]="item.classes?.subtitle"> *ngIf="item.subtitle">
{{item.subtitle}} <span [ngClass]="item.classes?.subtitle">
</span> {{item.subtitle}}
</div> </span>
</ng-container> </div>
</div> </div>
<!-- Badge --> <!-- Badge -->
<ng-container *ngIf="item.badge"> <div
<div class="fuse-vertical-navigation-item-badge"> class="fuse-vertical-navigation-item-badge"
<div *ngIf="item.badge">
class="fuse-vertical-navigation-item-badge-content" <div
[ngClass]="item.badge.classes"> class="fuse-vertical-navigation-item-badge-content"
{{item.badge.title}} [ngClass]="item.badge.classes">
</div> {{item.badge.title}}
</div> </div>
</ng-container> </div>
<!-- Arrow --> <!-- Arrow -->
<mat-icon <mat-icon
@@ -64,40 +62,35 @@
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden"> <ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Basic --> <!-- Basic -->
<ng-container *ngIf="item.type === 'basic'"> <fuse-vertical-navigation-basic-item
<fuse-vertical-navigation-basic-item *ngIf="item.type === 'basic'"
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-basic-item> [name]="name"></fuse-vertical-navigation-basic-item>
</ng-container>
<!-- Collapsable --> <!-- Collapsable -->
<ng-container *ngIf="item.type === 'collapsable'"> <fuse-vertical-navigation-collapsable-item
<fuse-vertical-navigation-collapsable-item *ngIf="item.type === 'collapsable'"
[item]="item" [item]="item"
[name]="name" [name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item> [autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item>
</ng-container>
<!-- Divider --> <!-- Divider -->
<ng-container *ngIf="item.type === 'divider'"> <fuse-vertical-navigation-divider-item
<fuse-vertical-navigation-divider-item *ngIf="item.type === 'divider'"
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-divider-item> [name]="name"></fuse-vertical-navigation-divider-item>
</ng-container>
<!-- Group --> <!-- Group -->
<ng-container *ngIf="item.type === 'group'"> <fuse-vertical-navigation-group-item
<fuse-vertical-navigation-group-item *ngIf="item.type === 'group'"
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-group-item> [name]="name"></fuse-vertical-navigation-group-item>
</ng-container>
<!-- Spacer --> <!-- Spacer -->
<ng-container *ngIf="item.type === 'spacer'"> <fuse-vertical-navigation-spacer-item
<fuse-vertical-navigation-spacer-item *ngIf="item.type === 'spacer'"
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-spacer-item> [name]="name"></fuse-vertical-navigation-spacer-item>
</ng-container>
</ng-container> </ng-container>

View File

@@ -1,7 +1,8 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostBinding, Input, OnDestroy, OnInit } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostBinding, Input, OnDestroy, OnInit } from '@angular/core';
import { NavigationEnd, Router } from '@angular/router'; import { NavigationEnd, Router } from '@angular/router';
import { BooleanInput } from '@angular/cdk/coercion'; import { BooleanInput } from '@angular/cdk/coercion';
import { filter, Subject, takeUntil } from 'rxjs'; import { Subject } from 'rxjs';
import { filter, takeUntil } from 'rxjs/operators';
import { fuseAnimations } from '@fuse/animations'; import { fuseAnimations } from '@fuse/animations';
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component'; import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
@@ -10,6 +11,7 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
@Component({ @Component({
selector : 'fuse-vertical-navigation-collapsable-item', selector : 'fuse-vertical-navigation-collapsable-item',
templateUrl : './collapsable.component.html', templateUrl : './collapsable.component.html',
styles : [],
animations : fuseAnimations, animations : fuseAnimations,
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}) })
@@ -175,7 +177,7 @@ export class FuseVerticalNavigationCollapsableItemComponent implements OnInit, O
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(null); this._unsubscribeAll.next();
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }

View File

@@ -1,5 +1,6 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
import { Subject, takeUntil } from 'rxjs'; import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component'; import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
@@ -7,6 +8,7 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
@Component({ @Component({
selector : 'fuse-vertical-navigation-divider-item', selector : 'fuse-vertical-navigation-divider-item',
templateUrl : './divider.component.html', templateUrl : './divider.component.html',
styles : [],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class FuseVerticalNavigationDividerItemComponent implements OnInit, OnDestroy export class FuseVerticalNavigationDividerItemComponent implements OnInit, OnDestroy
@@ -55,7 +57,7 @@ export class FuseVerticalNavigationDividerItemComponent implements OnInit, OnDes
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(null); this._unsubscribeAll.next();
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }
} }

View File

@@ -7,12 +7,11 @@
<div class="fuse-vertical-navigation-item"> <div class="fuse-vertical-navigation-item">
<!-- Icon --> <!-- Icon -->
<ng-container *ngIf="item.icon"> <mat-icon
<mat-icon class="fuse-vertical-navigation-item-icon"
class="fuse-vertical-navigation-item-icon" [ngClass]="item.classes?.icon"
[ngClass]="item.classes?.icon" *ngIf="item.icon"
[svgIcon]="item.icon"></mat-icon> [svgIcon]="item.icon"></mat-icon>
</ng-container>
<!-- Title & Subtitle --> <!-- Title & Subtitle -->
<div class="fuse-vertical-navigation-item-title-wrapper"> <div class="fuse-vertical-navigation-item-title-wrapper">
@@ -21,25 +20,25 @@
{{item.title}} {{item.title}}
</span> </span>
</div> </div>
<ng-container *ngIf="item.subtitle"> <div
<div class="fuse-vertical-navigation-item-subtitle"> class="fuse-vertical-navigation-item-subtitle"
<span [ngClass]="item.classes?.subtitle"> *ngIf="item.subtitle">
{{item.subtitle}} <span [ngClass]="item.classes?.subtitle">
</span> {{item.subtitle}}
</div> </span>
</ng-container> </div>
</div> </div>
<!-- Badge --> <!-- Badge -->
<ng-container *ngIf="item.badge"> <div
<div class="fuse-vertical-navigation-item-badge"> class="fuse-vertical-navigation-item-badge"
<div *ngIf="item.badge">
class="fuse-vertical-navigation-item-badge-content" <div
[ngClass]="item.badge.classes"> class="fuse-vertical-navigation-item-badge-content"
{{item.badge.title}} [ngClass]="item.badge.classes">
</div> {{item.badge.title}}
</div> </div>
</ng-container> </div>
</div> </div>
@@ -51,40 +50,35 @@
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden"> <ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Basic --> <!-- Basic -->
<ng-container *ngIf="item.type === 'basic'"> <fuse-vertical-navigation-basic-item
<fuse-vertical-navigation-basic-item *ngIf="item.type === 'basic'"
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-basic-item> [name]="name"></fuse-vertical-navigation-basic-item>
</ng-container>
<!-- Collapsable --> <!-- Collapsable -->
<ng-container *ngIf="item.type === 'collapsable'"> <fuse-vertical-navigation-collapsable-item
<fuse-vertical-navigation-collapsable-item *ngIf="item.type === 'collapsable'"
[item]="item" [item]="item"
[name]="name" [name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item> [autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item>
</ng-container>
<!-- Divider --> <!-- Divider -->
<ng-container *ngIf="item.type === 'divider'"> <fuse-vertical-navigation-divider-item
<fuse-vertical-navigation-divider-item *ngIf="item.type === 'divider'"
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-divider-item> [name]="name"></fuse-vertical-navigation-divider-item>
</ng-container>
<!-- Group --> <!-- Group -->
<ng-container *ngIf="item.type === 'group'"> <fuse-vertical-navigation-group-item
<fuse-vertical-navigation-group-item *ngIf="item.type === 'group'"
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-group-item> [name]="name"></fuse-vertical-navigation-group-item>
</ng-container>
<!-- Spacer --> <!-- Spacer -->
<ng-container *ngIf="item.type === 'spacer'"> <fuse-vertical-navigation-spacer-item
<fuse-vertical-navigation-spacer-item *ngIf="item.type === 'spacer'"
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-spacer-item> [name]="name"></fuse-vertical-navigation-spacer-item>
</ng-container>
</ng-container> </ng-container>

View File

@@ -1,6 +1,7 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
import { BooleanInput } from '@angular/cdk/coercion'; import { BooleanInput } from '@angular/cdk/coercion';
import { Subject, takeUntil } from 'rxjs'; import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component'; import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
@@ -8,6 +9,7 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
@Component({ @Component({
selector : 'fuse-vertical-navigation-group-item', selector : 'fuse-vertical-navigation-group-item',
templateUrl : './group.component.html', templateUrl : './group.component.html',
styles : [],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class FuseVerticalNavigationGroupItemComponent implements OnInit, OnDestroy export class FuseVerticalNavigationGroupItemComponent implements OnInit, OnDestroy
@@ -61,7 +63,7 @@ export class FuseVerticalNavigationGroupItemComponent implements OnInit, OnDestr
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(null); this._unsubscribeAll.next();
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }

View File

@@ -1,5 +1,6 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core';
import { Subject, takeUntil } from 'rxjs'; import { takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component'; import { FuseVerticalNavigationComponent } from '@fuse/components/navigation/vertical/vertical.component';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types'; import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types';
@@ -7,6 +8,7 @@ import { FuseNavigationItem } from '@fuse/components/navigation/navigation.types
@Component({ @Component({
selector : 'fuse-vertical-navigation-spacer-item', selector : 'fuse-vertical-navigation-spacer-item',
templateUrl : './spacer.component.html', templateUrl : './spacer.component.html',
styles : [],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class FuseVerticalNavigationSpacerItemComponent implements OnInit, OnDestroy export class FuseVerticalNavigationSpacerItemComponent implements OnInit, OnDestroy
@@ -55,7 +57,7 @@ export class FuseVerticalNavigationSpacerItemComponent implements OnInit, OnDest
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(null); this._unsubscribeAll.next();
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }
} }

View File

@@ -1,20 +1,20 @@
/* Variables */ /* Variables */
$fuse-vertical-navigation-compact-width: 112px; $fuse-vertical-navigation-compact-width: 112;
fuse-vertical-navigation { fuse-vertical-navigation {
/* Compact appearance overrides */ /* Compact appearance overrides */
&.fuse-vertical-navigation-appearance-compact { &.fuse-vertical-navigation-appearance-compact {
width: $fuse-vertical-navigation-compact-width; width: #{$fuse-vertical-navigation-compact-width}px;
min-width: $fuse-vertical-navigation-compact-width; min-width: #{$fuse-vertical-navigation-compact-width}px;
max-width: $fuse-vertical-navigation-compact-width; max-width: #{$fuse-vertical-navigation-compact-width}px;
/* Left positioned */ /* Left positioned */
&.fuse-vertical-navigation-position-left { &.fuse-vertical-navigation-position-left {
/* Side mode */ /* Side mode */
&.fuse-vertical-navigation-mode-side { &.fuse-vertical-navigation-mode-side {
margin-left: -$fuse-vertical-navigation-compact-width; margin-left: -#{$fuse-vertical-navigation-compact-width}px;
} }
/* Opened */ /* Opened */
@@ -28,7 +28,7 @@ fuse-vertical-navigation {
/* Side mode */ /* Side mode */
&.fuse-vertical-navigation-mode-side { &.fuse-vertical-navigation-mode-side {
margin-right: -$fuse-vertical-navigation-compact-width; margin-right: -#{$fuse-vertical-navigation-compact-width}px;
} }
/* Opened */ /* Opened */
@@ -39,7 +39,7 @@ fuse-vertical-navigation {
/* Aside wrapper */ /* Aside wrapper */
.fuse-vertical-navigation-aside-wrapper { .fuse-vertical-navigation-aside-wrapper {
left: auto; left: auto;
right: $fuse-vertical-navigation-compact-width; right: #{$fuse-vertical-navigation-compact-width}px;
} }
} }
@@ -104,7 +104,7 @@ fuse-vertical-navigation {
/* Aside wrapper */ /* Aside wrapper */
.fuse-vertical-navigation-aside-wrapper { .fuse-vertical-navigation-aside-wrapper {
left: $fuse-vertical-navigation-compact-width; left: #{$fuse-vertical-navigation-compact-width}px;
} }
} }
} }

View File

@@ -1,5 +1,5 @@
/* Variables */ /* Variables */
$fuse-vertical-navigation-width: 280px; $fuse-vertical-navigation-width: 280;
fuse-vertical-navigation { fuse-vertical-navigation {
position: sticky; position: sticky;
@@ -7,9 +7,9 @@ fuse-vertical-navigation {
flex-direction: column; flex-direction: column;
flex: 1 0 auto; flex: 1 0 auto;
top: 0; top: 0;
width: $fuse-vertical-navigation-width; width: #{$fuse-vertical-navigation-width}px;
min-width: $fuse-vertical-navigation-width; min-width: #{$fuse-vertical-navigation-width}px;
max-width: $fuse-vertical-navigation-width; max-width: #{$fuse-vertical-navigation-width}px;
height: 100vh; height: 100vh;
min-height: 100vh; min-height: 100vh;
max-height: 100vh; max-height: 100vh;
@@ -45,7 +45,7 @@ fuse-vertical-navigation {
/* Side mode */ /* Side mode */
&.fuse-vertical-navigation-mode-side { &.fuse-vertical-navigation-mode-side {
margin-left: -$fuse-vertical-navigation-width; margin-left: -#{$fuse-vertical-navigation-width}px;
&.fuse-vertical-navigation-opened { &.fuse-vertical-navigation-opened {
margin-left: 0; margin-left: 0;
@@ -73,7 +73,7 @@ fuse-vertical-navigation {
/* Side mode */ /* Side mode */
&.fuse-vertical-navigation-mode-side { &.fuse-vertical-navigation-mode-side {
margin-right: -$fuse-vertical-navigation-width; margin-right: -#{$fuse-vertical-navigation-width}px;
&.fuse-vertical-navigation-opened { &.fuse-vertical-navigation-opened {
margin-right: 0; margin-right: 0;
@@ -170,8 +170,8 @@ fuse-vertical-navigation {
flex-direction: column; flex-direction: column;
top: 0; top: 0;
bottom: 0; bottom: 0;
left: $fuse-vertical-navigation-width; left: #{$fuse-vertical-navigation-width}px;
width: $fuse-vertical-navigation-width; width: #{$fuse-vertical-navigation-width}px;
height: 100%; height: 100%;
z-index: 5; z-index: 5;
overflow-x: hidden; overflow-x: hidden;
@@ -196,7 +196,7 @@ fuse-vertical-navigation {
.fuse-vertical-navigation-aside-wrapper { .fuse-vertical-navigation-aside-wrapper {
left: auto; left: auto;
right: $fuse-vertical-navigation-width; right: #{$fuse-vertical-navigation-width}px;
} }
} }
@@ -335,7 +335,6 @@ fuse-vertical-navigation {
} }
> .fuse-vertical-navigation-item-children { > .fuse-vertical-navigation-item-children {
margin-top: 6px;
> *:last-child { > *:last-child {
padding-bottom: 6px; padding-bottom: 6px;

View File

@@ -1,6 +1,6 @@
/* Variables */ /* Variables */
$fuse-vertical-navigation-width: 280px; $fuse-vertical-navigation-width: 280;
$fuse-vertical-navigation-dense-width: 80px; $fuse-vertical-navigation-dense-width: 80;
fuse-vertical-navigation { fuse-vertical-navigation {
@@ -8,16 +8,16 @@ fuse-vertical-navigation {
&.fuse-vertical-navigation-appearance-dense { &.fuse-vertical-navigation-appearance-dense {
&:not(.fuse-vertical-navigation-mode-over) { &:not(.fuse-vertical-navigation-mode-over) {
width: $fuse-vertical-navigation-dense-width; width: #{$fuse-vertical-navigation-dense-width}px;
min-width: $fuse-vertical-navigation-dense-width; min-width: #{$fuse-vertical-navigation-dense-width}px;
max-width: $fuse-vertical-navigation-dense-width; max-width: #{$fuse-vertical-navigation-dense-width}px;
/* Left positioned */ /* Left positioned */
&.fuse-vertical-navigation-position-left { &.fuse-vertical-navigation-position-left {
/* Side mode */ /* Side mode */
&.fuse-vertical-navigation-mode-side { &.fuse-vertical-navigation-mode-side {
margin-left: -$fuse-vertical-navigation-dense-width; margin-left: -#{$fuse-vertical-navigation-dense-width}px;
} }
/* Opened */ /* Opened */
@@ -31,7 +31,7 @@ fuse-vertical-navigation {
/* Side mode */ /* Side mode */
&.fuse-vertical-navigation-mode-side { &.fuse-vertical-navigation-mode-side {
margin-right: -$fuse-vertical-navigation-dense-width; margin-right: -#{$fuse-vertical-navigation-dense-width}px;
} }
/* Opened */ /* Opened */
@@ -42,14 +42,14 @@ fuse-vertical-navigation {
/* Aside wrapper */ /* Aside wrapper */
.fuse-vertical-navigation-aside-wrapper { .fuse-vertical-navigation-aside-wrapper {
left: auto; left: auto;
right: $fuse-vertical-navigation-dense-width; right: #{$fuse-vertical-navigation-dense-width}px;
} }
&.fuse-vertical-navigation-hover { &.fuse-vertical-navigation-hover {
.fuse-vertical-navigation-aside-wrapper { .fuse-vertical-navigation-aside-wrapper {
left: auto; left: auto;
right: $fuse-vertical-navigation-width; right: #{$fuse-vertical-navigation-width}px;
} }
} }
} }
@@ -69,9 +69,9 @@ fuse-vertical-navigation {
.fuse-vertical-navigation-item-wrapper { .fuse-vertical-navigation-item-wrapper {
.fuse-vertical-navigation-item { .fuse-vertical-navigation-item {
width: $fuse-vertical-navigation-dense-width - 24px; width: #{$fuse-vertical-navigation-width}px - 24px;
min-width: $fuse-vertical-navigation-dense-width - 24px; min-width: #{$fuse-vertical-navigation-width}px - 24px;
max-width: $fuse-vertical-navigation-dense-width - 24px; max-width: #{$fuse-vertical-navigation-width}px - 24px;
.fuse-vertical-navigation-item-arrow, .fuse-vertical-navigation-item-arrow,
.fuse-vertical-navigation-item-badge, .fuse-vertical-navigation-item-badge,
@@ -142,23 +142,20 @@ fuse-vertical-navigation {
/* Aside wrapper */ /* Aside wrapper */
.fuse-vertical-navigation-aside-wrapper { .fuse-vertical-navigation-aside-wrapper {
left: $fuse-vertical-navigation-dense-width; left: #{$fuse-vertical-navigation-dense-width}px;
} }
/* Hover */ /* Hover */
&.fuse-vertical-navigation-hover { &.fuse-vertical-navigation-hover {
.fuse-vertical-navigation-wrapper { .fuse-vertical-navigation-wrapper {
width: $fuse-vertical-navigation-width; width: #{$fuse-vertical-navigation-width}px;
.fuse-vertical-navigation-content { .fuse-vertical-navigation-content {
.fuse-vertical-navigation-item-wrapper { .fuse-vertical-navigation-item-wrapper {
.fuse-vertical-navigation-item { .fuse-vertical-navigation-item {
width: $fuse-vertical-navigation-width - 24px;
min-width: $fuse-vertical-navigation-width - 24px;
max-width: $fuse-vertical-navigation-width - 24px;
.fuse-vertical-navigation-item-arrow, .fuse-vertical-navigation-item-arrow,
.fuse-vertical-navigation-item-badge, .fuse-vertical-navigation-item-badge,
@@ -173,7 +170,7 @@ fuse-vertical-navigation {
} }
.fuse-vertical-navigation-aside-wrapper { .fuse-vertical-navigation-aside-wrapper {
left: $fuse-vertical-navigation-width; left: #{$fuse-vertical-navigation-width}px;
} }
} }
} }

View File

@@ -1,19 +1,19 @@
/* Variables */ /* Variables */
$fuse-vertical-navigation-thin-width: 80px; $fuse-vertical-navigation-thin-width: 80;
fuse-vertical-navigation { fuse-vertical-navigation {
/* Thin appearance overrides */ /* Thin appearance overrides */
&.fuse-vertical-navigation-appearance-thin { &.fuse-vertical-navigation-appearance-thin {
width: $fuse-vertical-navigation-thin-width; width: #{$fuse-vertical-navigation-thin-width}px;
min-width: $fuse-vertical-navigation-thin-width; min-width: #{$fuse-vertical-navigation-thin-width}px;
max-width: $fuse-vertical-navigation-thin-width; max-width: #{$fuse-vertical-navigation-thin-width}px;
/* Left positioned */ /* Left positioned */
&.fuse-vertical-navigation-position-left { &.fuse-vertical-navigation-position-left {
&.fuse-vertical-navigation-mode-side { &.fuse-vertical-navigation-mode-side {
margin-left: -$fuse-vertical-navigation-thin-width; margin-left: -#{$fuse-vertical-navigation-thin-width}px;
} }
&.fuse-vertical-navigation-opened { &.fuse-vertical-navigation-opened {
@@ -25,7 +25,7 @@ fuse-vertical-navigation {
&.fuse-vertical-navigation-position-right { &.fuse-vertical-navigation-position-right {
&.fuse-vertical-navigation-mode-side { &.fuse-vertical-navigation-mode-side {
margin-right: -$fuse-vertical-navigation-thin-width; margin-right: -#{$fuse-vertical-navigation-thin-width}px;
} }
&.fuse-vertical-navigation-opened { &.fuse-vertical-navigation-opened {
@@ -34,7 +34,7 @@ fuse-vertical-navigation {
.fuse-vertical-navigation-aside-wrapper { .fuse-vertical-navigation-aside-wrapper {
left: auto; left: auto;
right: $fuse-vertical-navigation-thin-width; right: #{$fuse-vertical-navigation-thin-width}px;
} }
} }
@@ -91,7 +91,7 @@ fuse-vertical-navigation {
/* Aside wrapper */ /* Aside wrapper */
.fuse-vertical-navigation-aside-wrapper { .fuse-vertical-navigation-aside-wrapper {
left: $fuse-vertical-navigation-thin-width; left: #{$fuse-vertical-navigation-thin-width}px;
} }
} }
} }

View File

@@ -24,52 +24,46 @@
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden"> <ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Aside --> <!-- Aside -->
<ng-container *ngIf="item.type === 'aside'"> <fuse-vertical-navigation-aside-item
<fuse-vertical-navigation-aside-item *ngIf="item.type === 'aside'"
[item]="item" [item]="item"
[name]="name" [name]="name"
[activeItemId]="activeAsideItemId" [activeItemId]="activeAsideItemId"
[autoCollapse]="autoCollapse" [autoCollapse]="autoCollapse"
[skipChildren]="true" [skipChildren]="true"
(click)="toggleAside(item)"></fuse-vertical-navigation-aside-item> (click)="toggleAside(item)"></fuse-vertical-navigation-aside-item>
</ng-container>
<!-- Basic --> <!-- Basic -->
<ng-container *ngIf="item.type === 'basic'"> <fuse-vertical-navigation-basic-item
<fuse-vertical-navigation-basic-item *ngIf="item.type === 'basic'"
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-basic-item> [name]="name"></fuse-vertical-navigation-basic-item>
</ng-container>
<!-- Collapsable --> <!-- Collapsable -->
<ng-container *ngIf="item.type === 'collapsable'"> <fuse-vertical-navigation-collapsable-item
<fuse-vertical-navigation-collapsable-item *ngIf="item.type === 'collapsable'"
[item]="item" [item]="item"
[name]="name" [name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item> [autoCollapse]="autoCollapse"></fuse-vertical-navigation-collapsable-item>
</ng-container>
<!-- Divider --> <!-- Divider -->
<ng-container *ngIf="item.type === 'divider'"> <fuse-vertical-navigation-divider-item
<fuse-vertical-navigation-divider-item *ngIf="item.type === 'divider'"
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-divider-item> [name]="name"></fuse-vertical-navigation-divider-item>
</ng-container>
<!-- Group --> <!-- Group -->
<ng-container *ngIf="item.type === 'group'"> <fuse-vertical-navigation-group-item
<fuse-vertical-navigation-group-item *ngIf="item.type === 'group'"
[item]="item" [item]="item"
[name]="name" [name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-group-item> [autoCollapse]="autoCollapse"></fuse-vertical-navigation-group-item>
</ng-container>
<!-- Spacer --> <!-- Spacer -->
<ng-container *ngIf="item.type === 'spacer'"> <fuse-vertical-navigation-spacer-item
<fuse-vertical-navigation-spacer-item *ngIf="item.type === 'spacer'"
[item]="item" [item]="item"
[name]="name"></fuse-vertical-navigation-spacer-item> [name]="name"></fuse-vertical-navigation-spacer-item>
</ng-container>
</ng-container> </ng-container>
@@ -90,33 +84,31 @@
</div> </div>
<!-- Aside --> <!-- Aside -->
<ng-container *ngIf="activeAsideItemId"> <div
<div class="fuse-vertical-navigation-aside-wrapper"
class="fuse-vertical-navigation-aside-wrapper" *ngIf="activeAsideItemId"
fuseScrollbar fuseScrollbar
[fuseScrollbarOptions]="{wheelPropagation: false, suppressScrollX: true}" [fuseScrollbarOptions]="{wheelPropagation: false, suppressScrollX: true}"
[@fadeInLeft]="position === 'left'" [@fadeInLeft]="position === 'left'"
[@fadeInRight]="position === 'right'" [@fadeInRight]="position === 'right'"
[@fadeOutLeft]="position === 'left'" [@fadeOutLeft]="position === 'left'"
[@fadeOutRight]="position === 'right'"> [@fadeOutRight]="position === 'right'">
<!-- Items --> <!-- Items -->
<ng-container *ngFor="let item of navigation; trackBy: trackByFn"> <ng-container *ngFor="let item of navigation; trackBy: trackByFn">
<!-- Skip the hidden items --> <!-- Skip the hidden items -->
<ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden"> <ng-container *ngIf="(item.hidden && !item.hidden(item)) || !item.hidden">
<!-- Aside --> <!-- Aside -->
<ng-container *ngIf="item.type === 'aside' && item.id === activeAsideItemId"> <fuse-vertical-navigation-aside-item
<fuse-vertical-navigation-aside-item *ngIf="item.type === 'aside' && item.id === activeAsideItemId"
[item]="item" [item]="item"
[name]="name" [name]="name"
[autoCollapse]="autoCollapse"></fuse-vertical-navigation-aside-item> [autoCollapse]="autoCollapse"></fuse-vertical-navigation-aside-item>
</ng-container>
</ng-container>
</ng-container> </ng-container>
</div> </ng-container>
</ng-container>
</div>

View File

@@ -2,7 +2,8 @@ import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, E
import { animate, AnimationBuilder, AnimationPlayer, style } from '@angular/animations'; import { animate, AnimationBuilder, AnimationPlayer, style } from '@angular/animations';
import { NavigationEnd, Router } from '@angular/router'; import { NavigationEnd, Router } from '@angular/router';
import { ScrollStrategy, ScrollStrategyOptions } from '@angular/cdk/overlay'; import { ScrollStrategy, ScrollStrategyOptions } from '@angular/cdk/overlay';
import { delay, filter, merge, ReplaySubject, Subject, Subscription, takeUntil } from 'rxjs'; import { merge, ReplaySubject, Subject, Subscription } from 'rxjs';
import { delay, filter, takeUntil } from 'rxjs/operators';
import { fuseAnimations } from '@fuse/animations'; import { fuseAnimations } from '@fuse/animations';
import { FuseNavigationItem, FuseVerticalNavigationAppearance, FuseVerticalNavigationMode, FuseVerticalNavigationPosition } from '@fuse/components/navigation/navigation.types'; import { FuseNavigationItem, FuseVerticalNavigationAppearance, FuseVerticalNavigationMode, FuseVerticalNavigationPosition } from '@fuse/components/navigation/navigation.types';
import { FuseNavigationService } from '@fuse/components/navigation/navigation.service'; import { FuseNavigationService } from '@fuse/components/navigation/navigation.service';
@@ -72,10 +73,10 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
private _fuseUtilsService: FuseUtilsService private _fuseUtilsService: FuseUtilsService
) )
{ {
this._handleAsideOverlayClick = (): void => { this._handleAsideOverlayClick = () => {
this.closeAside(); this.closeAside();
}; };
this._handleOverlayClick = (): void => { this._handleOverlayClick = () => {
this.close(); this.close();
}; };
} }
@@ -373,15 +374,11 @@ export class FuseVerticalNavigationComponent implements OnChanges, OnInit, After
*/ */
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Forcefully close the navigation and aside in case they are opened
this.close();
this.closeAside();
// Deregister the navigation component from the registry // Deregister the navigation component from the registry
this._fuseNavigationService.deregisterComponent(this.name); this._fuseNavigationService.deregisterComponent(this.name);
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(null); this._unsubscribeAll.next();
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }

View File

@@ -0,0 +1,114 @@
import { ChangeDetectorRef, Directive, ElementRef, HostBinding, HostListener, Input, NgZone, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
import { Subject } from 'rxjs';
@Directive({
selector: 'textarea[fuseAutogrow]',
exportAs: 'fuseAutogrow'
})
export class FuseAutogrowDirective implements OnChanges, OnInit, OnDestroy
{
// eslint-disable-next-line @angular-eslint/no-input-rename
@Input('fuseAutogrowVerticalPadding') padding: number = 8;
@HostBinding('rows') private _rows: number = 1;
private _height: string = 'auto';
private _unsubscribeAll: Subject<any> = new Subject<any>();
/**
* Constructor
*/
constructor(
private _elementRef: ElementRef,
private _changeDetectorRef: ChangeDetectorRef,
private _ngZone: NgZone
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Host binding for component inline styles
*/
@HostBinding('style') get styleList(): any
{
return {
'height' : this._height,
'overflow': 'hidden',
'resize' : 'none'
};
}
// -----------------------------------------------------------------------------------------------------
// @ Decorated methods
// -----------------------------------------------------------------------------------------------------
/**
* Resize on 'input' and 'ngModelChange' events
*
* @private
*/
@HostListener('input')
@HostListener('ngModelChange')
private _resize(): void
{
// This doesn't need to trigger Angular's change detection by itself
this._ngZone.runOutsideAngular(() => {
setTimeout(() => {
// Set the height to 'auto' so we can correctly read the scrollHeight
this._height = 'auto';
// Detect the changes so the height is applied
this._changeDetectorRef.detectChanges();
// Get the scrollHeight and subtract the vertical padding
this._height = `${this._elementRef.nativeElement.scrollHeight - this.padding}px`;
// Detect the changes one more time to apply the final height
this._changeDetectorRef.detectChanges();
});
});
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On changes
*
* @param changes
*/
ngOnChanges(changes: SimpleChanges): void
{
// Padding
if ( 'fuseAutogrowVerticalPadding' in changes )
{
// Resize
this._resize();
}
}
/**
* On init
*/
ngOnInit(): void
{
// Resize for the first time
this._resize();
}
/**
* On destroy
*/
ngOnDestroy(): void
{
// Unsubscribe from all subscriptions
this._unsubscribeAll.next();
this._unsubscribeAll.complete();
}
}

View File

@@ -0,0 +1,14 @@
import { NgModule } from '@angular/core';
import { FuseAutogrowDirective } from '@fuse/directives/autogrow/autogrow.directive';
@NgModule({
declarations: [
FuseAutogrowDirective
],
exports : [
FuseAutogrowDirective
]
})
export class FuseAutogrowModule
{
}

View File

@@ -0,0 +1 @@
export * from '@fuse/directives/autogrow/public-api';

View File

@@ -0,0 +1,2 @@
export * from '@fuse/directives/autogrow/autogrow.directive';
export * from '@fuse/directives/autogrow/autogrow.module';

View File

@@ -1,6 +1,7 @@
import { Directive, ElementRef, OnDestroy, OnInit } from '@angular/core'; import { Directive, ElementRef, OnDestroy, OnInit } from '@angular/core';
import { NavigationEnd, Router } from '@angular/router'; import { NavigationEnd, Router } from '@angular/router';
import { filter, Subject, takeUntil } from 'rxjs'; import { Subject } from 'rxjs';
import { filter, takeUntil } from 'rxjs/operators';
@Directive({ @Directive({
selector: '[fuseScrollReset]', selector: '[fuseScrollReset]',
@@ -46,7 +47,7 @@ export class FuseScrollResetDirective implements OnInit, OnDestroy
ngOnDestroy(): void ngOnDestroy(): void
{ {
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(null); this._unsubscribeAll.next();
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }
} }

View File

@@ -2,7 +2,8 @@ import { Directive, ElementRef, Input, OnChanges, OnDestroy, OnInit, SimpleChang
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion'; import { BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';
import { Platform } from '@angular/cdk/platform'; import { Platform } from '@angular/cdk/platform';
import { debounceTime, fromEvent, Subject, takeUntil } from 'rxjs'; import { fromEvent, Subject } from 'rxjs';
import { debounceTime, takeUntil } from 'rxjs/operators';
import PerfectScrollbar from 'perfect-scrollbar'; import PerfectScrollbar from 'perfect-scrollbar';
import { merge } from 'lodash-es'; import { merge } from 'lodash-es';
import { ScrollbarGeometry, ScrollbarPosition } from '@fuse/directives/scrollbar/scrollbar.types'; import { ScrollbarGeometry, ScrollbarPosition } from '@fuse/directives/scrollbar/scrollbar.types';
@@ -137,7 +138,7 @@ export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy
this._destroy(); this._destroy();
// Unsubscribe from all subscriptions // Unsubscribe from all subscriptions
this._unsubscribeAll.next(null); this._unsubscribeAll.next();
this._unsubscribeAll.complete(); this._unsubscribeAll.complete();
} }
@@ -388,7 +389,7 @@ export class FuseScrollbarDirective implements OnChanges, OnInit, OnDestroy
const cosParameter = (oldValue - value) / 2; const cosParameter = (oldValue - value) / 2;
const step = (newTimestamp: number): void => { const step = (newTimestamp: number) => {
scrollCount += Math.PI / (speed / (newTimestamp - oldTimestamp)); scrollCount += Math.PI / (speed / (newTimestamp - oldTimestamp));
newValue = Math.round(value + cosParameter + cosParameter * Math.cos(scrollCount)); newValue = Math.round(value + cosParameter + cosParameter * Math.cos(scrollCount));

View File

@@ -1,30 +1,18 @@
import { NgModule, Optional, SkipSelf } from '@angular/core'; import { NgModule, Optional, SkipSelf } from '@angular/core';
import { MATERIAL_SANITY_CHECKS } from '@angular/material/core';
import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field'; import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field';
import { FuseConfirmationModule } from '@fuse/services/confirmation';
import { FuseLoadingModule } from '@fuse/services/loading';
import { FuseMediaWatcherModule } from '@fuse/services/media-watcher/media-watcher.module'; import { FuseMediaWatcherModule } from '@fuse/services/media-watcher/media-watcher.module';
import { FuseSplashScreenModule } from '@fuse/services/splash-screen/splash-screen.module'; import { FuseSplashScreenModule } from '@fuse/services/splash-screen/splash-screen.module';
import { FuseTailwindConfigModule } from '@fuse/services/tailwind/tailwind.module';
import { FuseUtilsModule } from '@fuse/services/utils/utils.module'; import { FuseUtilsModule } from '@fuse/services/utils/utils.module';
@NgModule({ @NgModule({
imports : [ imports : [
FuseConfirmationModule,
FuseLoadingModule,
FuseMediaWatcherModule, FuseMediaWatcherModule,
FuseSplashScreenModule, FuseSplashScreenModule,
FuseTailwindConfigModule,
FuseUtilsModule FuseUtilsModule
], ],
providers: [ providers: [
{
// Disable 'theme' sanity check
provide : MATERIAL_SANITY_CHECKS,
useValue: {
doctype: true,
theme : false,
version: true
}
},
{ {
// Use the 'fill' appearance on Angular Material form fields by default // Use the 'fill' appearance on Angular Material form fields by default
provide : MAT_FORM_FIELD_DEFAULT_OPTIONS, provide : MAT_FORM_FIELD_DEFAULT_OPTIONS,

View File

@@ -1,6 +1,7 @@
import { Inject, Injectable } from '@angular/core'; import { Inject, Injectable } from '@angular/core';
import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http'; import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http';
import { delay, Observable, of, switchMap, throwError } from 'rxjs'; import { Observable, of, throwError } from 'rxjs';
import { delay, switchMap } from 'rxjs/operators';
import { FUSE_MOCK_API_DEFAULT_DELAY } from '@fuse/lib/mock-api/mock-api.constants'; import { FUSE_MOCK_API_DEFAULT_DELAY } from '@fuse/lib/mock-api/mock-api.constants';
import { FuseMockApiService } from '@fuse/lib/mock-api/mock-api.service'; import { FuseMockApiService } from '@fuse/lib/mock-api/mock-api.service';
@@ -50,7 +51,7 @@ export class FuseMockApiInterceptor implements HttpInterceptor
delay(handler.delay ?? this._defaultDelay ?? 0), delay(handler.delay ?? this._defaultDelay ?? 0),
switchMap((response) => { switchMap((response) => {
// If there is no response data, // If there is no response mock-api,
// throw an error response // throw an error response
if ( !response ) if ( !response )
{ {
@@ -63,7 +64,7 @@ export class FuseMockApiInterceptor implements HttpInterceptor
return throwError(response); return throwError(response);
} }
// Parse the response data // Parse the response mock-api
const data = { const data = {
status: response[0], status: response[0],
body : response[1] body : response[1]

View File

@@ -29,7 +29,7 @@ export class FuseMockApiModule
{ {
provide : APP_INITIALIZER, provide : APP_INITIALIZER,
deps : [...mockApiServices], deps : [...mockApiServices],
useFactory: () => (): any => null, useFactory: () => () => null,
multi : true multi : true
}, },
{ {

View File

@@ -1,5 +1,6 @@
import { HttpRequest } from '@angular/common/http'; import { HttpRequest } from '@angular/common/http';
import { Observable, of, take, throwError } from 'rxjs'; import { Observable, of, throwError } from 'rxjs';
import { take } from 'rxjs/operators';
import { FuseMockApiReplyCallback } from '@fuse/lib/mock-api/mock-api.types'; import { FuseMockApiReplyCallback } from '@fuse/lib/mock-api/mock-api.types';
export class FuseMockApiHandler export class FuseMockApiHandler

View File

@@ -9,14 +9,11 @@ import { FuseMockApiMethods } from '@fuse/lib/mock-api/mock-api.types';
export class FuseMockApiService export class FuseMockApiService
{ {
private _handlers: { [key: string]: Map<string, FuseMockApiHandler> } = { private _handlers: { [key: string]: Map<string, FuseMockApiHandler> } = {
'get' : new Map<string, FuseMockApiHandler>(), 'delete': new Map<string, FuseMockApiHandler>(),
'post' : new Map<string, FuseMockApiHandler>(), 'get' : new Map<string, FuseMockApiHandler>(),
'patch' : new Map<string, FuseMockApiHandler>(), 'patch' : new Map<string, FuseMockApiHandler>(),
'delete' : new Map<string, FuseMockApiHandler>(), 'post' : new Map<string, FuseMockApiHandler>(),
'put' : new Map<string, FuseMockApiHandler>(), 'put' : new Map<string, FuseMockApiHandler>()
'head' : new Map<string, FuseMockApiHandler>(),
'jsonp' : new Map<string, FuseMockApiHandler>(),
'options': new Map<string, FuseMockApiHandler>()
}; };
/** /**
@@ -89,40 +86,7 @@ export class FuseMockApiService
} }
/** /**
* Register GET request handler * Register a DELETE request handler
*
* @param url - URL address of the mocked API endpoint
* @param delay - Delay of the response in milliseconds
*/
onGet(url: string, delay?: number): FuseMockApiHandler
{
return this._registerHandler('get', url, delay);
}
/**
* Register POST request handler
*
* @param url - URL address of the mocked API endpoint
* @param delay - Delay of the response in milliseconds
*/
onPost(url: string, delay?: number): FuseMockApiHandler
{
return this._registerHandler('post', url, delay);
}
/**
* Register PATCH request handler
*
* @param url - URL address of the mocked API endpoint
* @param delay - Delay of the response in milliseconds
*/
onPatch(url: string, delay?: number): FuseMockApiHandler
{
return this._registerHandler('patch', url, delay);
}
/**
* Register DELETE request handler
* *
* @param url - URL address of the mocked API endpoint * @param url - URL address of the mocked API endpoint
* @param delay - Delay of the response in milliseconds * @param delay - Delay of the response in milliseconds
@@ -133,7 +97,40 @@ export class FuseMockApiService
} }
/** /**
* Register PUT request handler * Register a GET request handler
*
* @param url - URL address of the mocked API endpoint
* @param delay - Delay of the response in milliseconds
*/
onGet(url: string, delay?: number): FuseMockApiHandler
{
return this._registerHandler('get', url, delay);
}
/**
* Register a PATCH request handler
*
* @param url - URL address of the mocked API endpoint
* @param delay - Delay of the response in milliseconds
*/
onPatch(url: string, delay?: number): FuseMockApiHandler
{
return this._registerHandler('patch', url, delay);
}
/**
* Register a POST request handler
*
* @param url - URL address of the mocked API endpoint
* @param delay - Delay of the response in milliseconds
*/
onPost(url: string, delay?: number): FuseMockApiHandler
{
return this._registerHandler('post', url, delay);
}
/**
* Register a PUT request handler
* *
* @param url - URL address of the mocked API endpoint * @param url - URL address of the mocked API endpoint
* @param delay - Delay of the response in milliseconds * @param delay - Delay of the response in milliseconds
@@ -143,39 +140,6 @@ export class FuseMockApiService
return this._registerHandler('put', url, delay); return this._registerHandler('put', url, delay);
} }
/**
* Register HEAD request handler
*
* @param url - URL address of the mocked API endpoint
* @param delay - Delay of the response in milliseconds
*/
onHead(url: string, delay?: number): FuseMockApiHandler
{
return this._registerHandler('head', url, delay);
}
/**
* Register JSONP request handler
*
* @param url - URL address of the mocked API endpoint
* @param delay - Delay of the response in milliseconds
*/
onJsonp(url: string, delay?: number): FuseMockApiHandler
{
return this._registerHandler('jsonp', url, delay);
}
/**
* Register OPTIONS request handler
*
* @param url - URL address of the mocked API endpoint
* @param delay - Delay of the response in milliseconds
*/
onOptions(url: string, delay?: number): FuseMockApiHandler
{
return this._registerHandler('options', url, delay);
}
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
// @ Private methods // @ Private methods
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------

View File

@@ -8,9 +8,6 @@ export type FuseMockApiReplyCallback =
export type FuseMockApiMethods = export type FuseMockApiMethods =
| 'get' | 'get'
| 'post' | 'post'
| 'patch'
| 'delete'
| 'put' | 'put'
| 'head' | 'patch'
| 'jsonp' | 'delete';
| 'options';

View File

@@ -1,31 +0,0 @@
import { NgModule } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatDialogModule } from '@angular/material/dialog';
import { MatIconModule } from '@angular/material/icon';
import { FuseConfirmationService } from '@fuse/services/confirmation/confirmation.service';
import { FuseConfirmationDialogComponent } from '@fuse/services/confirmation/dialog/dialog.component';
import { CommonModule } from '@angular/common';
@NgModule({
declarations: [
FuseConfirmationDialogComponent
],
imports : [
MatButtonModule,
MatDialogModule,
MatIconModule,
CommonModule
],
providers : [
FuseConfirmationService
]
})
export class FuseConfirmationModule
{
/**
* Constructor
*/
constructor(private _fuseConfirmationService: FuseConfirmationService)
{
}
}

View File

@@ -1,58 +0,0 @@
import { Injectable } from '@angular/core';
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
import { merge } from 'lodash-es';
import { FuseConfirmationDialogComponent } from '@fuse/services/confirmation/dialog/dialog.component';
import { FuseConfirmationConfig } from '@fuse/services/confirmation/confirmation.types';
@Injectable()
export class FuseConfirmationService
{
private _defaultConfig: FuseConfirmationConfig = {
title : 'Confirm action',
message : 'Are you sure you want to confirm this action?',
icon : {
show : true,
name : 'heroicons_outline:exclamation',
color: 'warn'
},
actions : {
confirm: {
show : true,
label: 'Confirm',
color: 'warn'
},
cancel : {
show : true,
label: 'Cancel'
}
},
dismissible: false
};
/**
* Constructor
*/
constructor(
private _matDialog: MatDialog
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
open(config: FuseConfirmationConfig = {}): MatDialogRef<FuseConfirmationDialogComponent>
{
// Merge the user config with the default config
const userConfig = merge({}, this._defaultConfig, config);
// Open the dialog
return this._matDialog.open(FuseConfirmationDialogComponent, {
autoFocus : false,
disableClose: !userConfig.dismissible,
data : userConfig,
panelClass : 'fuse-confirmation-dialog-panel'
});
}
}

View File

@@ -1,22 +0,0 @@
export interface FuseConfirmationConfig
{
title?: string;
message?: string;
icon?: {
show?: boolean;
name?: string;
color?: 'primary' | 'accent' | 'warn' | 'basic' | 'info' | 'success' | 'warning' | 'error';
};
actions?: {
confirm?: {
show?: boolean;
label?: string;
color?: 'primary' | 'accent' | 'warn';
};
cancel?: {
show?: boolean;
label?: string;
};
};
dismissible?: boolean;
}

View File

@@ -1,85 +0,0 @@
<div class="relative flex flex-col w-full h-full">
<!-- Dismiss button -->
<ng-container *ngIf="data.dismissible">
<div class="absolute top-0 right-0 pt-4 pr-4">
<button
mat-icon-button
[matDialogClose]="undefined">
<mat-icon
class="text-secondary"
[svgIcon]="'heroicons_outline:x'"></mat-icon>
</button>
</div>
</ng-container>
<!-- Content -->
<div class="flex flex-col sm:flex-row flex-auto items-center sm:items-start p-8 pb-6 sm:pb-8">
<!-- Icon -->
<ng-container *ngIf="data.icon.show">
<div
class="flex flex-0 items-center justify-center w-10 h-10 sm:mr-4 rounded-full"
[ngClass]="{'text-primary-600 bg-primary-100 dark:text-primary-50 dark:bg-primary-600': data.icon.color === 'primary',
'text-accent-600 bg-accent-100 dark:text-accent-50 dark:bg-accent-600': data.icon.color === 'accent',
'text-warn-600 bg-warn-100 dark:text-warn-50 dark:bg-warn-600': data.icon.color === 'warn',
'text-gray-600 bg-gray-100 dark:text-gray-50 dark:bg-gray-600': data.icon.color === 'basic',
'text-blue-600 bg-blue-100 dark:text-blue-50 dark:bg-blue-600': data.icon.color === 'info',
'text-green-500 bg-green-100 dark:text-green-50 dark:bg-green-500': data.icon.color === 'success',
'text-amber-500 bg-amber-100 dark:text-amber-50 dark:bg-amber-500': data.icon.color === 'warning',
'text-red-600 bg-red-100 dark:text-red-50 dark:bg-red-600': data.icon.color === 'error'
}">
<mat-icon
class="text-current"
[svgIcon]="data.icon.name"></mat-icon>
</div>
</ng-container>
<ng-container *ngIf="data.title || data.message">
<div class="flex flex-col items-center sm:items-start mt-4 sm:mt-0 sm:pr-8 space-y-1 text-center sm:text-left">
<!-- Title -->
<ng-container *ngIf="data.title">
<div
class="text-xl leading-6 font-medium"
[innerHTML]="data.title"></div>
</ng-container>
<!-- Message -->
<ng-container *ngIf="data.message">
<div
class="text-secondary"
[innerHTML]="data.message"></div>
</ng-container>
</div>
</ng-container>
</div>
<!-- Actions -->
<ng-container *ngIf="data.actions.confirm.show || data.actions.cancel.show">
<div class="flex items-center justify-center sm:justify-end px-6 py-4 space-x-3 bg-gray-50 dark:bg-black dark:bg-opacity-10">
<!-- Cancel -->
<ng-container *ngIf="data.actions.cancel.show">
<button
mat-stroked-button
[matDialogClose]="'cancelled'">
{{data.actions.cancel.label}}
</button>
</ng-container>
<!-- Confirm -->
<ng-container *ngIf="data.actions.confirm.show">
<button
mat-flat-button
[color]="data.actions.confirm.color"
[matDialogClose]="'confirmed'">
{{data.actions.confirm.label}}
</button>
</ng-container>
</div>
</ng-container>
</div>

View File

@@ -1,52 +0,0 @@
import { Component, Inject, OnInit, ViewEncapsulation } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { FuseConfirmationConfig } from '@fuse/services/confirmation/confirmation.types';
@Component({
selector : 'fuse-confirmation-dialog',
templateUrl : './dialog.component.html',
styles : [
/* language=SCSS */
`
.fuse-confirmation-dialog-panel {
@screen md {
@apply w-128;
}
.mat-dialog-container {
padding: 0 !important;
}
}
`
],
encapsulation: ViewEncapsulation.None
})
export class FuseConfirmationDialogComponent implements OnInit
{
/**
* Constructor
*/
constructor(
@Inject(MAT_DIALOG_DATA) public data: FuseConfirmationConfig,
public matDialogRef: MatDialogRef<FuseConfirmationDialogComponent>
)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
}

View File

@@ -1 +0,0 @@
export * from '@fuse/services/confirmation/public-api';

View File

@@ -1,3 +0,0 @@
export * from '@fuse/services/confirmation/confirmation.module';
export * from '@fuse/services/confirmation/confirmation.service';
export * from '@fuse/services/confirmation/confirmation.types';

View File

@@ -1 +0,0 @@
export * from '@fuse/services/loading/public-api';

View File

@@ -1,48 +0,0 @@
import { Injectable } from '@angular/core';
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { finalize, Observable } from 'rxjs';
import { FuseLoadingService } from '@fuse/services/loading/loading.service';
@Injectable()
export class FuseLoadingInterceptor implements HttpInterceptor
{
handleRequestsAutomatically: boolean;
/**
* Constructor
*/
constructor(
private _fuseLoadingService: FuseLoadingService
)
{
// Subscribe to the auto
this._fuseLoadingService.auto$
.subscribe((value) => {
this.handleRequestsAutomatically = value;
});
}
/**
* Intercept
*
* @param req
* @param next
*/
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>
{
// If the Auto mode is turned off, do nothing
if ( !this.handleRequestsAutomatically )
{
return next.handle(req);
}
// Set the loading status to true
this._fuseLoadingService._setLoadingStatus(true, req.url);
return next.handle(req).pipe(
finalize(() => {
// Set the status to false if there are any errors or the request is completed
this._fuseLoadingService._setLoadingStatus(false, req.url);
}));
}
}

View File

@@ -1,16 +0,0 @@
import { NgModule } from '@angular/core';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { FuseLoadingInterceptor } from '@fuse/services/loading/loading.interceptor';
@NgModule({
providers: [
{
provide : HTTP_INTERCEPTORS,
useClass: FuseLoadingInterceptor,
multi : true
}
]
})
export class FuseLoadingModule
{
}

View File

@@ -1,146 +0,0 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class FuseLoadingService
{
private _auto$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
private _mode$: BehaviorSubject<'determinate' | 'indeterminate'> = new BehaviorSubject<'determinate' | 'indeterminate'>('indeterminate');
private _progress$: BehaviorSubject<number | null> = new BehaviorSubject<number | null>(0);
private _show$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
private _urlMap: Map<string, boolean> = new Map<string, boolean>();
/**
* Constructor
*/
constructor(private _httpClient: HttpClient)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Getter for auto mode
*/
get auto$(): Observable<boolean>
{
return this._auto$.asObservable();
}
/**
* Getter for mode
*/
get mode$(): Observable<'determinate' | 'indeterminate'>
{
return this._mode$.asObservable();
}
/**
* Getter for progress
*/
get progress$(): Observable<number>
{
return this._progress$.asObservable();
}
/**
* Getter for show
*/
get show$(): Observable<boolean>
{
return this._show$.asObservable();
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------
/**
* Show the loading bar
*/
show(): void
{
this._show$.next(true);
}
/**
* Hide the loading bar
*/
hide(): void
{
this._show$.next(false);
}
/**
* Set the auto mode
*
* @param value
*/
setAutoMode(value: boolean): void
{
this._auto$.next(value);
}
/**
* Set the mode
*
* @param value
*/
setMode(value: 'determinate' | 'indeterminate'): void
{
this._mode$.next(value);
}
/**
* Set the progress of the bar manually
*
* @param value
*/
setProgress(value: number): void
{
if ( value < 0 || value > 100 )
{
console.error('Progress value must be between 0 and 100!');
return;
}
this._progress$.next(value);
}
/**
* Sets the loading status on the given url
*
* @param status
* @param url
*/
_setLoadingStatus(status: boolean, url: string): void
{
// Return if the url was not provided
if ( !url )
{
console.error('The request URL must be provided!');
return;
}
if ( status === true )
{
this._urlMap.set(url, status);
this._show$.next(true);
}
else if ( status === false && this._urlMap.has(url) )
{
this._urlMap.delete(url);
}
// Only set the status to 'false' if all outgoing requests are completed
if ( this._urlMap.size === 0 )
{
this._show$.next(false);
}
}
}

View File

@@ -1,2 +0,0 @@
export * from '@fuse/services/loading/loading.service';
export * from '@fuse/services/loading/loading.module';

View File

@@ -1,8 +1,8 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout'; import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout';
import { map, Observable, ReplaySubject, switchMap } from 'rxjs'; import { Observable, ReplaySubject } from 'rxjs';
import { fromPairs } from 'lodash-es'; import { map, switchMap } from 'rxjs/operators';
import { FuseConfigService } from '@fuse/services/config'; import { FuseTailwindService } from '@fuse/services/tailwind/tailwind.service';
@Injectable() @Injectable()
export class FuseMediaWatcherService export class FuseMediaWatcherService
@@ -14,12 +14,11 @@ export class FuseMediaWatcherService
*/ */
constructor( constructor(
private _breakpointObserver: BreakpointObserver, private _breakpointObserver: BreakpointObserver,
private _fuseConfigService: FuseConfigService private _fuseTailwindConfigService: FuseTailwindService
) )
{ {
this._fuseConfigService.config$.pipe( this._fuseTailwindConfigService.tailwindConfig$.pipe(
map(config => fromPairs(Object.entries(config.screens).map(([alias, screen]) => ([alias, `(min-width: ${screen})`])))), switchMap(config => this._breakpointObserver.observe(Object.values(config.breakpoints)).pipe(
switchMap(screens => this._breakpointObserver.observe(Object.values(screens)).pipe(
map((state) => { map((state) => {
// Prepare the observable values and set their defaults // Prepare the observable values and set their defaults
@@ -31,7 +30,7 @@ export class FuseMediaWatcherService
for ( const [query] of matchingBreakpoints ) for ( const [query] of matchingBreakpoints )
{ {
// Find the alias of the matching query // Find the alias of the matching query
const matchingAlias = Object.entries(screens).find(([alias, q]) => q === query)[0]; const matchingAlias = Object.entries(config.breakpoints).find(([alias, q]) => q === query)[0];
// Add the matching query to the observable values // Add the matching query to the observable values
if ( matchingAlias ) if ( matchingAlias )

View File

@@ -1,7 +1,7 @@
import { Inject, Injectable } from '@angular/core'; import { Inject, Injectable } from '@angular/core';
import { DOCUMENT } from '@angular/common'; import { DOCUMENT } from '@angular/common';
import { NavigationEnd, Router } from '@angular/router'; import { NavigationEnd, Router } from '@angular/router';
import { filter, take } from 'rxjs'; import { filter, take } from 'rxjs/operators';
@Injectable() @Injectable()
export class FuseSplashScreenService export class FuseSplashScreenService

View File

@@ -0,0 +1 @@
export * from '@fuse/services/media-watcher/public-api';

View File

@@ -0,0 +1,2 @@
export * from '@fuse/services/media-watcher/media-watcher.module';
export * from '@fuse/services/media-watcher/media-watcher.service';

View File

@@ -0,0 +1,17 @@
import { NgModule } from '@angular/core';
import { FuseTailwindService } from '@fuse/services/tailwind/tailwind.service';
@NgModule({
providers: [
FuseTailwindService
]
})
export class FuseTailwindConfigModule
{
/**
* Constructor
*/
constructor(private _fuseTailwindConfigService: FuseTailwindService)
{
}
}

View File

@@ -0,0 +1,58 @@
import { Injectable } from '@angular/core';
import { Observable, ReplaySubject } from 'rxjs';
import { fromPairs, map } from 'lodash-es';
import * as extractedTailwindConfigStyle from '@fuse/styles/core/tailwind-config.scss';
@Injectable()
export class FuseTailwindService
{
private _tailwindConfig: ReplaySubject<any> = new ReplaySubject<any>(1);
/**
* Constructor
*/
constructor()
{
// Prepare the config object
const config: any = {};
// Extract the style from the class
const regexpForClass = /\.fuse-tailwind-extracted-config\s\{([\s\S]*)\}/g;
const style = regexpForClass.exec(extractedTailwindConfigStyle.default)[1].trim();
// Extract the rules
const regexp = /(--[\s\S]*?):'([\s\S]*?)';/g;
let rules = regexp.exec(style);
// Add to the config
while ( rules !== null )
{
const configGroup = /--([\s\S]*?)-/g.exec(rules[1])[1];
if ( !config[configGroup] )
{
config[configGroup] = {};
}
config[configGroup][rules[1].replace(/(--[\s\S]*?-)/g, '')] = rules[2];
rules = regexp.exec(style);
}
// Parse the themes objects
config.themes = fromPairs(map(config.themes, (value, key) => [key, JSON.parse(value)]));
// Execute the observable with the config
this._tailwindConfig.next(config);
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Getter for _tailwindConfig
*/
get tailwindConfig$(): Observable<any>
{
return this._tailwindConfig.asObservable();
}
}

View File

@@ -1 +1 @@
export * from '@fuse/services/utils/public-api'; export * from '@fuse/services/config/public-api';

View File

@@ -1,5 +1,4 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { IsActiveMatchOptions } from '@angular/router';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@@ -13,36 +12,6 @@ export class FuseUtilsService
{ {
} }
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
/**
* Get the equivalent "IsActiveMatchOptions" options for "exact = true".
*/
get exactMatchOptions(): IsActiveMatchOptions
{
return {
paths : 'exact',
fragment : 'ignored',
matrixParams: 'ignored',
queryParams : 'exact'
};
}
/**
* Get the equivalent "IsActiveMatchOptions" options for "exact = false".
*/
get subsetMatchOptions(): IsActiveMatchOptions
{
return {
paths : 'subset',
fragment : 'ignored',
matrixParams: 'ignored',
queryParams : 'subset'
};
}
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
// @ Public methods // @ Public methods
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------

View File

@@ -0,0 +1,6 @@
/* ----------------------------------------------------------------------------------------------------- */
/* @ Any configuration we need from Tailwind's config file will be extracted here so we can import this
/* @ file from "config.ts" to access the extracted configuration from TypeScript
/* ----------------------------------------------------------------------------------------------------- */
@variants fuse-tailwind-extracted-config {
}

View File

@@ -1,9 +1,13 @@
/* 1. Components */ /* 1. Core */
@import 'core/tailwind-config';
/* 2. Components */
@import 'components/example-viewer'; @import 'components/example-viewer';
@import 'components/input'; @import 'components/input';
/* 2. Overrides */ /* 3. Overrides */
@import 'overrides/angular-material'; @import 'overrides/angular-material';
@import 'overrides/fullcalendar';
@import 'overrides/highlightjs'; @import 'overrides/highlightjs';
@import 'overrides/perfect-scrollbar'; @import 'overrides/perfect-scrollbar';
@import 'overrides/quill'; @import 'overrides/quill';

View File

@@ -136,8 +136,11 @@
.mat-flat-button, .mat-flat-button,
.mat-raised-button, .mat-raised-button,
.mat-stroked-button { .mat-stroked-button {
padding: 0 20px !important;
border-radius: 9999px !important; .fuse-mat-rounded & {
padding: 0 20px;
border-radius: 9999px;
}
} }
/* Target all buttons */ /* Target all buttons */
@@ -175,7 +178,11 @@
/* Add hover and focus style on all buttons */ /* Add hover and focus style on all buttons */
.mat-button-focus-overlay { .mat-button-focus-overlay {
@apply bg-gray-400 bg-opacity-20 dark:bg-black dark:bg-opacity-5 #{'!important'}; @apply bg-gray-400 bg-opacity-20 #{'!important'};
.dark & {
background-color: rgba(0, 0, 0, 0.05) !important;
}
} }
/* On palette colored buttons, use a darker color */ /* On palette colored buttons, use a darker color */
@@ -246,7 +253,11 @@
/* Add hover and focus styles */ /* Add hover and focus styles */
.mat-button-focus-overlay { .mat-button-focus-overlay {
@apply bg-gray-400 bg-opacity-20 dark:bg-black dark:bg-opacity-5 #{'!important'}; @apply bg-gray-400 bg-opacity-20 #{'!important'};
.dark & {
background-color: rgba(0, 0, 0, 0.05) !important;
}
} }
/* On primary colored buttons, use the primary color as focus overlay */ /* On primary colored buttons, use the primary color as focus overlay */
@@ -319,11 +330,19 @@
/* Border color */ /* Border color */
&:not(.mat-button-disabled) { &:not(.mat-button-disabled) {
@apply border-gray-300 dark:border-gray-500 #{'!important'}; @apply border-gray-300 #{'!important'};
.dark & {
@apply border-gray-500 #{'!important'};
}
} }
&.mat-button-disabled { &.mat-button-disabled {
@apply border-gray-200 dark:border-gray-600 #{'!important'}; @apply border-gray-200 #{'!important'};
.dark & {
@apply border-gray-600 #{'!important'};
}
} }
} }
@@ -331,8 +350,6 @@
/* @ Button Toggle /* @ Button Toggle
/* ----------------------------------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------------------------------- */
.mat-button-toggle-group { .mat-button-toggle-group {
border: none !important;
@apply space-x-1;
&.mat-button-toggle-group-appearance-standard { &.mat-button-toggle-group-appearance-standard {
@@ -340,27 +357,36 @@
background-clip: padding-box; background-clip: padding-box;
} }
} }
}
.mat-button-toggle { /* Rounded design */
border-radius: 9999px; .fuse-mat-rounded {
overflow: hidden;
.mat-button-toggle-group {
border: none !important; border: none !important;
font-weight: 500; @apply space-x-1;
&.mat-button-toggle-checked { .mat-button-toggle {
border-radius: 9999px;
overflow: hidden;
border: none !important;
font-weight: 500;
&.mat-button-toggle-checked {
.mat-button-toggle-label-content {
@apply text-default #{'!important'};
}
}
.mat-button-toggle-label-content { .mat-button-toggle-label-content {
@apply text-default #{'!important'}; padding: 0 20px;
@apply text-secondary;
} }
}
.mat-button-toggle-label-content { .mat-ripple {
padding: 0 20px; border-radius: 9999px;
@apply text-secondary; }
}
.mat-ripple {
border-radius: 9999px;
} }
} }
} }
@@ -400,13 +426,6 @@
font-weight: 500 !important; font-weight: 500 !important;
} }
/* ----------------------------------------------------------------------------------------------------- */
/* @ Dialog
/* ----------------------------------------------------------------------------------------------------- */
.mat-dialog-container {
border-radius: 16px !important;
}
/* ----------------------------------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------------------------------- */
/* @ Drawer /* @ Drawer
/* ----------------------------------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------------------------------- */
@@ -434,7 +453,7 @@
/* Border color */ /* Border color */
.mat-form-field-flex { .mat-form-field-flex {
@apply border-warn dark:border-warn #{'!important'}; @apply border-warn #{'!important'};
} }
} }
} }
@@ -446,7 +465,7 @@
/* Background color */ /* Background color */
.mat-form-field-flex { .mat-form-field-flex {
@apply bg-card dark:bg-card #{'!important'}; @apply bg-card #{'!important'};
} }
} }
} }
@@ -458,7 +477,7 @@
/* Border color */ /* Border color */
.mat-form-field-flex { .mat-form-field-flex {
@apply border-primary dark:border-primary #{'!important'}; @apply border-primary #{'!important'};
} }
} }
} }
@@ -523,7 +542,13 @@
border-radius: 6px; border-radius: 6px;
padding: 0 16px; padding: 0 16px;
border-width: 1px; border-width: 1px;
@apply shadow-sm bg-white border-gray-300 dark:bg-black dark:bg-opacity-5 dark:border-gray-500 #{'!important'}; background-color: white;
@apply border-gray-300 shadow-sm #{'!important'};
.dark & {
background-color: rgba(0, 0, 0, 0.05) !important;
@apply border-gray-500 #{'!important'};
}
.mat-form-field-prefix { .mat-form-field-prefix {
@@ -608,28 +633,12 @@
@apply icon-size-6; @apply icon-size-6;
} }
/* Make mat-select usable as prefix and suffix */ /* Make mat-select usable as */
/* prefix and suffix */
.mat-select { .mat-select {
display: flex; display: flex;
align-items: center; align-items: center;
&:focus {
.mat-select-trigger {
.mat-select-value {
@apply text-primary #{'!important'};
}
.mat-select-arrow-wrapper {
.mat-select-arrow {
border-top-color: var(--fuse-primary) !important;
}
}
}
}
.mat-select-trigger { .mat-select-trigger {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -654,7 +663,6 @@
.mat-select-arrow { .mat-select-arrow {
min-height: 0; min-height: 0;
@apply text-gray-500 dark:text-gray-400 #{'!important'};
} }
} }
} }
@@ -680,8 +688,8 @@
align-self: stretch; align-self: stretch;
min-height: 36px; min-height: 36px;
height: auto; height: auto;
margin: 14px 0; margin: 10px 0;
padding: 0 6px 0 0; padding: 4px 6px 4px 0 !important;
transform: none; transform: none;
} }
@@ -1024,7 +1032,11 @@
.mat-form-field-prefix, .mat-form-field-prefix,
.mat-form-field-suffix { .mat-form-field-suffix {
@apply bg-default border-gray-300 dark:border-gray-500 #{'!important'}; @apply border-gray-300 bg-default #{'!important'};
.dark & {
@apply border-gray-500 #{'!important'};
}
} }
} }
} }
@@ -1319,55 +1331,62 @@
opacity: 0 !important; opacity: 0 !important;
} }
} }
.mat-tab-header {
border-bottom: none !important;
.mat-tab-label-container {
padding: 0 24px;
.mat-tab-list {
.mat-tab-labels {
.mat-tab-label {
min-width: 0 !important;
height: 40px !important;
padding: 0 20px !important;
border-radius: 9999px !important;
@apply text-secondary;
&.mat-tab-label-active {
@apply bg-gray-700 bg-opacity-10 dark:bg-gray-50 dark:bg-opacity-10 #{'!important'};
@apply text-default #{'!important'};
}
+ .mat-tab-label {
margin-left: 4px;
}
.mat-tab-label-content {
line-height: 20px;
}
}
}
.mat-ink-bar {
display: none !important;
}
}
}
}
.mat-tab-body-content {
padding: 24px;
}
} }
.mat-tab-label { .mat-tab-label {
opacity: 1 !important; opacity: 1 !important;
} }
/* Rounded design */
.fuse-mat-rounded {
.mat-tab-group {
.mat-tab-header {
border-bottom: none !important;
.mat-tab-label-container {
padding: 0 24px;
.mat-tab-list {
.mat-tab-labels {
.mat-tab-label {
min-width: 0 !important;
height: 40px !important;
padding: 0 20px !important;
border-radius: 9999px !important;
@apply text-secondary;
&.mat-tab-label-active {
@apply bg-gray-700 bg-opacity-10 dark:bg-gray-50 dark:bg-opacity-10 #{'!important'};
@apply text-default #{'!important'};
}
+ .mat-tab-label {
margin-left: 4px;
}
.mat-tab-label-content {
line-height: 20px;
}
}
}
.mat-ink-bar {
display: none !important;
}
}
}
}
.mat-tab-body-content {
padding: 24px;
}
}
}
/* ----------------------------------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------------------------------- */
/* @ Textarea /* @ Textarea
/* ----------------------------------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------------------------------- */

View File

@@ -0,0 +1,680 @@
/* ----------------------------------------------------------------------------------------------------- */
/* @ FullCalendar overrides
/* ----------------------------------------------------------------------------------------------------- */
.fc {
.fc-view-container {
/* Day Grid - Month view */
.fc-view.fc-dayGridMonth-view {
.fc-head {
> tr > .fc-head-container {
border: none;
.fc-row {
.fc-day-header {
border-color: var(--fuse-divider);
span {
display: flex;
align-items: center;
justify-content: center;
padding-top: 8px;
font-size: 12px;
font-weight: 500;
text-transform: uppercase;
@apply text-secondary;
}
}
}
}
}
.fc-body {
> tr > .fc-widget-content {
border: none;
.fc-day-grid {
.fc-week {
.fc-bg {
.fc-day {
border-color: var(--fuse-divider);
&.fc-today {
background: none;
}
}
}
.fc-content-skeleton {
.fc-day-top {
text-align: center;
&.fc-other-month {
opacity: 1;
.fc-day-number {
@apply text-hint;
}
}
&.fc-today {
.fc-day-number {
@apply bg-primary text-on-primary;
}
}
.fc-day-number {
display: inline-flex;
align-items: center;
justify-content: center;
width: 22px;
height: 21px;
margin: 4px 0;
font-size: 12px;
border-radius: 50%;
float: none;
}
}
.fc-event-container {
.fc-day-grid-event {
display: flex;
align-items: center;
height: 22px;
min-height: 22px;
max-height: 22px;
margin: 0 6px 4px 6px;
padding: 0 5px;
font-size: 12px;
border-radius: 4px;
border: none;
cursor: pointer;
@screen sm {
padding: 0 8px;
}
}
}
.fc-more {
padding: 0 3px;
font-size: 12px;
font-weight: 500;
white-space: nowrap;
@apply text-secondary;
@screen sm {
padding: 0 6px;
}
}
}
.fc-highlight-skeleton {
.fc-highlight {
position: relative;
opacity: 1;
@apply bg-gray-100;
}
}
}
}
}
}
.fc-popover {
@apply bg-card;
&.fc-more-popover {
border: none;
border-radius: 4px;
@apply shadow-2xl;
.fc-header {
height: 32px;
min-height: 32px;
max-height: 32px;
padding: 0 8px;
@apply bg-hover;
.fc-title {
margin: 0;
padding: 0;
font-size: 12px;
}
}
.fc-body {
max-height: 160px;
overflow: hidden auto;
.fc-event-container {
padding: 8px;
.fc-day-grid-event {
display: flex;
align-items: center;
height: 22px;
min-height: 22px;
max-height: 22px;
margin: 0 0 6px 0;
padding: 0 8px;
font-size: 12px;
line-height: 1;
border-radius: 4px;
border: none;
cursor: pointer;
&:last-child {
margin-bottom: 0;
}
}
}
}
}
}
}
/* Time Grid - Week view */
.fc-view.fc-timeGridWeek-view {
.fc-head {
> tr > .fc-head-container {
border: none;
.fc-row {
.fc-axis {
width: 48px !important;
border-color: var(--fuse-divider);
}
.fc-day-header {
border-color: var(--fuse-divider);
span {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
@apply text-secondary;
&.fc-weekday {
padding-top: 16px;
font-size: 12px;
letter-spacing: 0.055em;
text-transform: uppercase;
font-weight: 400;
}
&.fc-date {
padding-bottom: 12px;
font-size: 26px;
font-weight: 300;
}
}
}
}
}
}
.fc-body {
> tr > .fc-widget-content {
border: none;
.fc-day-grid {
.fc-row {
min-height: 0;
.fc-bg {
.fc-axis {
width: 48px !important;
border-color: var(--fuse-divider);
}
.fc-day {
border-color: var(--fuse-divider);
&.fc-today {
background: none;
}
}
}
.fc-content-skeleton {
padding-bottom: 0;
.fc-axis {
width: 48px !important;
}
.fc-event-container {
.fc-day-grid-event {
display: flex;
align-items: center;
height: 22px;
min-height: 22px;
max-height: 22px;
margin: 0 6px 6px 6px;
padding: 0 8px;
font-size: 12px;
line-height: 1;
border-radius: 4px;
border: none;
cursor: pointer;
}
}
}
}
}
.fc-divider {
border: none;
background: var(--fuse-divider);
}
.fc-time-grid {
.fc-bg {
.fc-axis {
border: none;
width: 48px !important;
+ .fc-day {
border: none;
}
}
.fc-day {
border-color: var(--fuse-divider);
&.fc-today {
background: none;
}
}
}
.fc-slats {
.fc-axis {
width: 48px !important;
height: 48px;
text-align: center;
span {
font-size: 12px;
width: 48px;
min-width: 48px;
}
}
.fc-time {
border-color: var(--fuse-divider);
}
.fc-widget-content {
border-color: var(--fuse-divider);
}
}
.fc-content-skeleton {
.fc-axis {
width: 48px !important;
}
.fc-event-container {
margin: 0 12px 0 0;
.fc-time-grid-event {
display: flex;
padding: 8px;
border-radius: 4px;
border: none;
cursor: pointer;
.fc-time,
.fc-title {
font-size: 12px;
}
}
}
}
}
}
}
}
/* Time Grid - Day view */
.fc-view.fc-timeGridDay-view {
.fc-head {
> tr > .fc-head-container {
border: none;
.fc-row {
.fc-axis {
width: 48px !important;
border-color: var(--fuse-divider);
}
.fc-day-header {
border-color: var(--fuse-divider);
span {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
@apply text-secondary;
&.fc-weekday {
padding-top: 16px;
font-size: 12px;
letter-spacing: 0.055em;
text-transform: uppercase;
font-weight: 400;
}
&.fc-date {
padding-bottom: 12px;
font-size: 26px;
font-weight: 300;
}
}
}
}
}
}
.fc-body {
> tr > .fc-widget-content {
border: none;
.fc-day-grid {
.fc-bg {
.fc-axis {
border-color: var(--fuse-divider);
}
.fc-day {
border-color: var(--fuse-divider);
&.fc-today {
background: none;
}
}
}
.fc-row {
min-height: 0;
.fc-bg {
.fc-axis {
width: 48px !important;
}
}
.fc-content-skeleton {
padding-bottom: 0;
.fc-axis {
width: 48px !important;
}
.fc-event-container {
.fc-day-grid-event {
display: flex;
align-items: center;
height: 22px;
min-height: 22px;
max-height: 22px;
margin: 0 6px 6px 6px;
padding: 0 8px;
font-size: 12px;
line-height: 1;
border-radius: 4px;
border: none;
cursor: pointer;
}
}
}
}
}
.fc-divider {
border: none;
border-color: var(--fuse-divider);
}
.fc-time-grid {
.fc-bg {
.fc-day {
border-color: var(--fuse-divider);
&.fc-today {
background: none;
}
}
.fc-axis {
border: none;
width: 48px !important;
+ .fc-day {
border: none;
}
}
}
.fc-slats {
.fc-axis {
width: 48px !important;
height: 48px;
text-align: center;
span {
font-size: 12px;
width: 48px;
min-width: 48px;
}
}
.fc-time {
border-color: var(--fuse-divider);
}
.fc-widget-content {
border-color: var(--fuse-divider);
}
}
.fc-content-skeleton {
.fc-axis {
width: 48px !important;
}
.fc-event-container {
margin: 0 12px 0 0;
.fc-time-grid-event {
display: flex;
padding: 8px;
border-radius: 4px;
border: none;
cursor: pointer;
.fc-time,
.fc-title {
font-size: 12px;
}
}
}
}
}
}
}
}
/* List - Year view */
.fc-view.fc-listYear-view {
border: none;
.fc-list-table {
.fc-list-heading {
display: none;
}
.fc-list-item {
display: flex;
cursor: pointer;
&:hover {
td {
@apply bg-hover;
}
}
td {
display: flex;
align-items: center;
width: auto;
height: 48px;
min-height: 48px;
padding: 0 8px;
border-width: 0 0 1px 0;
border-color: var(--fuse-divider);
&.fc-list-item-date {
order: 1;
padding-left: 16px;
width: 100px;
min-width: 100px;
max-width: 100px;
@screen sm {
width: 120px;
min-width: 120px;
max-width: 120px;
}
> span {
display: flex;
align-items: baseline;
span {
&:first-child {
display: flex;
justify-content: center;
padding-right: 2px;
width: 32px;
min-width: 32px;
max-width: 32px;
font-size: 18px;
@screen sm {
padding-right: 8px;
}
+ span {
display: flex;
font-size: 11px;
font-weight: 500;
letter-spacing: 0.055em;
text-transform: uppercase;
@apply text-secondary;
}
}
}
}
}
&.fc-list-item-time {
flex: 0 0 auto;
order: 3;
width: 120px;
min-width: 120px;
max-width: 120px;
@screen sm {
width: 160px;
min-width: 160px;
max-width: 160px;
}
}
&.fc-list-item-marker {
flex: 0 0 auto;
order: 2;
.fc-event-dot {
width: 12px;
height: 12px;
border-radius: 50%;
}
}
&.fc-list-item-title {
flex: 1 1 auto;
order: 4;
padding-right: 24px;
font-weight: 500;
}
}
}
}
}
}
/* Day grid event - Dragging */
.fc-day-grid-event {
&.fc-dragging,
&.fc-resizing {
display: flex;
align-items: center;
height: 22px;
min-height: 22px;
max-height: 22px;
margin: 0 6px 4px 6px;
padding: 0 8px;
font-size: 12px;
line-height: 1;
border-radius: 4px;
border: none;
}
}
}

View File

@@ -4,12 +4,11 @@
.ql-toolbar { .ql-toolbar {
border-radius: 6px 6px 0 0; border-radius: 6px 6px 0 0;
padding: 0 !important; padding: 0 !important;
@apply bg-gray-100; @apply bg-gray-100 border-gray-300;
@apply border-gray-300 border-opacity-100 #{'!important'};
.dark & { .dark & {
background-color: rgba(0, 0, 0, 0.05); background-color: rgba(0, 0, 0, 0.05);
@apply border-gray-500 #{'!important'}; @apply border-gray-500;
} }
.ql-formats { .ql-formats {
@@ -82,22 +81,26 @@
.ql-container { .ql-container {
overflow: hidden; overflow: hidden;
border-radius: 0 0 6px 6px; border-radius: 0 0 6px 6px;
@apply border-gray-300 border-opacity-100 shadow-sm #{'!important'}; @apply border-gray-300 shadow-sm;
.dark & { .dark & {
@apply border-gray-500 #{'!important'}; @apply border-gray-500;
} }
.ql-editor { .ql-editor {
min-height: 160px; min-height: 160px;
max-height: 160px; max-height: 160px;
height: 160px; height: 160px;
@apply bg-card; @apply bg-gray-50;
.dark & { .dark & {
background-color: rgba(0, 0, 0, 0.05); background-color: rgba(0, 0, 0, 0.05);
} }
&:focus {
@apply bg-card;
}
&.ql-blank::before { &.ql-blank::before {
@apply text-hint; @apply text-hint;
} }

View File

@@ -1,24 +1,96 @@
@use '@angular/material' as mat; @use '~@angular/material' as mat;
@use "sass:map"; @use "sass:map";
/* Include the core Angular Material styles */ /** Include the core Angular Material styles */
@include mat.core(); @include mat.core();
/* Create a base theme without color. /** Configure the Angular Material typography */
This will globally set the density and typography for all future color themes. */ @include mat.all-component-typographies(
@include mat.all-component-themes(( mat.define-typography-config(
color: null, $font-family: theme('fontFamily.sans'),
density: -2, $title: mat.define-typography-level(1.25rem, 2rem, 600),
typography: mat.define-typography-config( $body-2: mat.define-typography-level(0.875rem, 1.5rem, 600),
$font-family: theme('fontFamily.sans'), $button: mat.define-typography-level(0.875rem, 0.875rem, 500),
$title: mat.define-typography-level(1.25rem, 2rem, 600), $input: mat.define-typography-level(0.875rem, 1.2857142857, 400) // line-height: 20px
$body-2: mat.define-typography-level(0.875rem, 1.5rem, 600), )
$button: mat.define-typography-level(0.875rem, 0.875rem, 500), );
$input: mat.define-typography-level(0.875rem, 1.2857142857, 400) /* line-height: 20px */
)
));
/* Generate Primary, Accent and Warn palettes */ /** Prepare the Background and Foreground maps */
$background-light: (
status-bar: #CBD5E1, /* blueGray.300 */
app-bar: #FFFFFF,
background: #F1F5F9, /* blueGray.100 */
hover: rgba(148, 163, 184, 0.12), /* blueGray.400 + opacity */
card: #FFFFFF,
dialog: #FFFFFF,
disabled-button: rgba(148, 163, 184, 0.38), /* blueGray.400 + opacity */
raised-button: #FFFFFF,
focused-button: #64748B, /* blueGray.500 */
selected-button: #E2E8F0, /* blueGray.200 */
selected-disabled-button: #E2E8F0, /* blueGray.200 */
disabled-button-toggle: #CBD5E1, /* blueGray.300 */
unselected-chip: #E2E8F0, /* blueGray.200 */
disabled-list-option: #CBD5E1, /* blueGray.300 */
tooltip: #1E293B /* blueGray.800 */
);
$background-dark: (
status-bar: #0F172A, /* blueGray.900 */
app-bar: #0F172A, /* blueGray.900 */
background: #0F172A, /* blueGray.900 */
hover: rgba(255, 255, 255, 0.05),
card: #1E293B, /* blueGray.800 */
dialog: #1E293B, /* blueGray.800 */
disabled-button: rgba(15, 23, 42, 0.38), /* blueGray.900 + opacity */
raised-button: #0F172A, /* blueGray.900 */
focused-button: #E2E8F0, /* blueGray.200 */
selected-button: rgba(255, 255, 255, 0.05),
selected-disabled-button: #1E293B, /* blueGray.800 */
disabled-button-toggle: #0F172A, /* blueGray.900 */
unselected-chip: #475569, /* blueGray.600 */
disabled-list-option: #E2E8F0, /* blueGray.200 */
tooltip: #64748B /* blueGray.500 */
);
$foreground-light: (
base: #000000,
divider: #E2E8F0, /* blueGray.200 */
dividers: #E2E8F0, /* blueGray.200 */
disabled: #94A3B8, /* blueGray.400 */
disabled-button: #94A3B8, /* blueGray.400 */
disabled-text: #94A3B8, /* blueGray.400 */
elevation: #000000,
hint-text: #94A3B8, /* blueGray.400 */
secondary-text: #64748B, /* blueGray.500 */
icon: #64748B, /* blueGray.500 */
icons: #64748B, /* blueGray.500 */
mat-icon: #64748B, /* blueGray.500 */
text: #1E293B, /* blueGray.800 */
slider-min: #1E293B, /* blueGray.800 */
slider-off: #CBD5E1, /* blueGray.300 */
slider-off-active: #94A3B8 /* blueGray.400 */
);
$foreground-dark: (
base: #FFFFFF,
divider: rgba(241, 245, 249, 0.12), /* blueGray.100 + opacity */
dividers: rgba(241, 245, 249, 0.12), /* blueGray.100 + opacity */
disabled: #475569, /* blueGray.600 */
disabled-button: #1E293B, /* blueGray.800 */
disabled-text: #475569, /* blueGray.600 */
elevation: #000000,
hint-text: #64748B, /* blueGray.500 */
secondary-text: #94A3B8, /* blueGray.400 */
icon: #F1F5F9, /* blueGray.100 */
icons: #F1F5F9, /* blueGray.100 */
mat-icon: #94A3B8, /* blueGray.400 */
text: #FFFFFF,
slider-min: #FFFFFF,
slider-off: #64748B, /* blueGray.500 */
slider-off-active: #94A3B8 /* blueGray.400 */
);
/** Generate Primary, Accent and Warn palettes */
$palettes: (); $palettes: ();
@each $name in (primary, accent, warn) { @each $name in (primary, accent, warn) {
$palettes: map.merge($palettes, (#{$name}: ( $palettes: map.merge($palettes, (#{$name}: (
@@ -54,7 +126,7 @@ $palettes: ();
))); )));
} }
/* Generate Angular Material themes. Since we are using CSS Custom Properties, /** Generate Angular Material themes. Since we are using CSS Custom Properties,
we don't have to generate a separate Angular Material theme for each color we don't have to generate a separate Angular Material theme for each color
set. We can just create one light and one dark theme and then switch the set. We can just create one light and one dark theme and then switch the
CSS Custom Properties to dynamically switch the colors. */ CSS Custom Properties to dynamically switch the colors. */
@@ -70,46 +142,13 @@ body .light {
accent: map.get(map.get($base-light-theme, color), accent), accent: map.get(map.get($base-light-theme, color), accent),
warn: map.get(map.get($base-light-theme, color), warn), warn: map.get(map.get($base-light-theme, color), warn),
is-dark: map.get(map.get($base-light-theme, color), is-dark), is-dark: map.get(map.get($base-light-theme, color), is-dark),
foreground: ( foreground: $foreground-light,
base: #000000, background: $background-light
divider: #E2E8F0, /* slate.200 */ ),
dividers: #E2E8F0, /* slate.200 */ density: -2
disabled: #94A3B8, /* slate.400 */
disabled-button: #94A3B8, /* slate.400 */
disabled-text: #94A3B8, /* slate.400 */
elevation: #000000,
hint-text: #94A3B8, /* slate.400 */
secondary-text: #64748B, /* slate.500 */
icon: #64748B, /* slate.500 */
icons: #64748B, /* slate.500 */
mat-icon: #64748B, /* slate.500 */
text: #1E293B, /* slate.800 */
slider-min: #1E293B, /* slate.800 */
slider-off: #CBD5E1, /* slate.300 */
slider-off-active: #94A3B8 /* slate.400 */
),
background: (
status-bar: #CBD5E1, /* slate.300 */
app-bar: #FFFFFF,
background: #F1F5F9, /* slate.100 */
hover: rgba(148, 163, 184, 0.12), /* slate.400 + opacity */
card: #FFFFFF,
dialog: #FFFFFF,
disabled-button: rgba(148, 163, 184, 0.38), /* slate.400 + opacity */
raised-button: #FFFFFF,
focused-button: #64748B, /* slate.500 */
selected-button: #E2E8F0, /* slate.200 */
selected-disabled-button: #E2E8F0, /* slate.200 */
disabled-button-toggle: #CBD5E1, /* slate.300 */
unselected-chip: #E2E8F0, /* slate.200 */
disabled-list-option: #CBD5E1, /* slate.300 */
tooltip: #1E293B /* slate.800 */
)
)
); );
/* Use all-component-colors to only generate the colors */ @include mat.all-component-themes($light-theme);
@include mat.all-component-colors($light-theme);
} }
body.dark, body.dark,
@@ -124,44 +163,11 @@ body .dark {
accent: map.get(map.get($base-dark-theme, color), accent), accent: map.get(map.get($base-dark-theme, color), accent),
warn: map.get(map.get($base-dark-theme, color), warn), warn: map.get(map.get($base-dark-theme, color), warn),
is-dark: map.get(map.get($base-dark-theme, color), is-dark), is-dark: map.get(map.get($base-dark-theme, color), is-dark),
foreground: ( foreground: $foreground-dark,
base: #FFFFFF, background: $background-dark
divider: rgba(241, 245, 249, 0.12), /* slate.100 + opacity */ ),
dividers: rgba(241, 245, 249, 0.12), /* slate.100 + opacity */ density: -2
disabled: #475569, /* slate.600 */
disabled-button: #1E293B, /* slate.800 */
disabled-text: #475569, /* slate.600 */
elevation: #000000,
hint-text: #64748B, /* slate.500 */
secondary-text: #94A3B8, /* slate.400 */
icon: #F1F5F9, /* slate.100 */
icons: #F1F5F9, /* slate.100 */
mat-icon: #94A3B8, /* slate.400 */
text: #FFFFFF,
slider-min: #FFFFFF,
slider-off: #64748B, /* slate.500 */
slider-off-active: #94A3B8 /* slate.400 */
),
background: (
status-bar: #0F172A, /* slate.900 */
app-bar: #0F172A, /* slate.900 */
background: #0F172A, /* slate.900 */
hover: rgba(255, 255, 255, 0.05),
card: #1E293B, /* slate.800 */
dialog: #1E293B, /* slate.800 */
disabled-button: rgba(15, 23, 42, 0.38), /* slate.900 + opacity */
raised-button: #0F172A, /* slate.900 */
focused-button: #E2E8F0, /* slate.200 */
selected-button: rgba(255, 255, 255, 0.05),
selected-disabled-button: #1E293B, /* slate.800 */
disabled-button-toggle: #0F172A, /* slate.900 */
unselected-chip: #475569, /* slate.600 */
disabled-list-option: #E2E8F0, /* slate.200 */
tooltip: #64748B /* slate.500 */
)
)
); );
/* Use all-component-colors to only generate the colors */
@include mat.all-component-colors($dark-theme); @include mat.all-component-colors($dark-theme);
} }

View File

@@ -0,0 +1,38 @@
const plugin = require('tailwindcss/plugin');
const buildMediaQuery = require('tailwindcss/lib/util/buildMediaQuery').default;
const extractConfig = plugin(({
addVariant,
theme
}) =>
{
addVariant('fuse-tailwind-extracted-config', ({container}) =>
{
// Prepare the extracted config variable
let extractedConfig = '';
// Breakpoints
Object.entries(theme('screens')).forEach(([key, value]) =>
{
extractedConfig = `${extractedConfig} --breakpoints-${key}:'${buildMediaQuery(value)}';`;
});
// Themes
(theme('fuse.themes')).forEach((value) =>
{
Object.entries(value).forEach(([key, value]) =>
{
extractedConfig = `${extractedConfig} --themes-${key}:'${JSON.stringify(value)}';`;
});
});
// Append the extracted config
container.append(`
.fuse-tailwind-extracted-config {
${extractedConfig}
}
`);
});
});
module.exports = extractConfig;

View File

@@ -1,14 +1,17 @@
const plugin = require('tailwindcss/plugin'); const plugin = require('tailwindcss/plugin');
module.exports = plugin( const iconSize = plugin(({
({ addUtilities,
matchUtilities, theme,
theme e,
variants
}) => }) =>
{ {
matchUtilities( const values = theme('iconSize');
{
'icon-size': (value) => ({ addUtilities(
Object.entries(values).map(([key, value]) => ({
[`.${e(`icon-size-${key}`)}`]: {
width : value, width : value,
height : value, height : value,
minWidth : value, minWidth : value,
@@ -19,14 +22,13 @@ module.exports = plugin(
width : value, width : value,
height: value height: value
} }
}) }
}, })),
{ variants('iconSize')
values: theme('iconSize') );
});
}, },
{ {
theme: { theme : {
iconSize: { iconSize: {
3 : '0.75rem', 3 : '0.75rem',
3.5: '0.875rem', 3.5: '0.875rem',
@@ -45,6 +47,10 @@ module.exports = plugin(
22 : '5.5rem', 22 : '5.5rem',
24 : '6rem' 24 : '6rem'
} }
},
variants: {
iconSize: ['responsive']
} }
} });
);
module.exports = iconSize;

View File

@@ -102,7 +102,7 @@ const theming = plugin.withOptions((options) => ({
// @ Map variable colors // @ Map variable colors
// ----------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------
const mapVariableColors = _.fromPairs(_.map(options.themes, (theme, themeName) => [ const mapVariableColors = _.fromPairs(_.map(options.themes, (theme, themeName) => [
themeName === 'default' ? 'body, .theme-default' : `.theme-${e(themeName)}`, themeName === 'default' ? 'body' : `body.theme-${e(themeName)}`,
_.fromPairs(_.flatten(_.map(flattenColorPalette(_.fromPairs(_.flatten(_.map(normalizeTheme(theme), (palette, paletteName) => [ _.fromPairs(_.flatten(_.map(flattenColorPalette(_.fromPairs(_.flatten(_.map(normalizeTheme(theme), (palette, paletteName) => [
[ [
e(paletteName), e(paletteName),
@@ -185,46 +185,47 @@ const theming = plugin.withOptions((options) => ({
light: { light: {
'bg-app-bar' : '#FFFFFF', 'bg-app-bar' : '#FFFFFF',
'bg-card' : '#FFFFFF', 'bg-card' : '#FFFFFF',
'bg-default' : colors.slate[100], 'bg-default' : colors.blueGray[100],
'bg-dialog' : '#FFFFFF', 'bg-dialog' : '#FFFFFF',
'bg-hover' : chroma(colors.slate[400]).alpha(0.12).css(), 'bg-hover' : chroma(colors.blueGray[400]).alpha(0.12).css(),
'bg-status-bar': colors.slate[300] 'bg-status-bar': colors.blueGray[300]
}, },
dark : { dark : {
'bg-app-bar' : colors.slate[900], 'bg-app-bar' : colors.blueGray[900],
'bg-card' : colors.slate[800], 'bg-card' : colors.blueGray[800],
'bg-default' : colors.slate[900], 'bg-default' : colors.blueGray[900],
'bg-dialog' : colors.slate[800], 'bg-dialog' : colors.blueGray[800],
'bg-hover' : 'rgba(255, 255, 255, 0.05)', 'bg-hover' : 'rgba(255, 255, 255, 0.05)',
'bg-status-bar': colors.slate[900] 'bg-status-bar': colors.blueGray[900]
} }
}, },
foreground: { foreground: {
light: { light: {
'text-default' : colors.slate[800], 'text-default' : colors.blueGray[800],
'text-secondary': colors.slate[500], 'text-secondary': colors.blueGray[500],
'text-hint' : colors.slate[400], 'text-hint' : colors.blueGray[400],
'text-disabled' : colors.slate[400], 'text-disabled' : colors.blueGray[400],
'border' : colors.slate[200], 'border' : colors.blueGray[200],
'divider' : colors.slate[200], 'divider' : colors.blueGray[200],
'icon' : colors.slate[500], 'icon' : colors.blueGray[500],
'mat-icon' : colors.slate[500] 'mat-icon' : colors.blueGray[500]
}, },
dark : { dark : {
'text-default' : '#FFFFFF', 'text-default' : '#FFFFFF',
'text-secondary': colors.slate[400], 'text-secondary': colors.blueGray[400],
'text-hint' : colors.slate[500], 'text-hint' : colors.blueGray[500],
'text-disabled' : colors.slate[600], 'text-disabled' : colors.blueGray[600],
'border' : chroma(colors.slate[100]).alpha(0.12).css(), 'border' : chroma(colors.blueGray[100]).alpha(0.12).css(),
'divider' : chroma(colors.slate[100]).alpha(0.12).css(), 'divider' : chroma(colors.blueGray[100]).alpha(0.12).css(),
'icon' : colors.slate[400], 'icon' : colors.blueGray[400],
'mat-icon' : colors.slate[400] 'mat-icon' : colors.blueGray[400]
} }
} }
}, },
themes : generateThemesObject(options.themes) themes : generateThemesObject(options.themes)
} }
} },
variants: {}
}; };
} }
); );

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