Merge branch 'dev' into dev-starter

This commit is contained in:
Sercan Yemen 2024-03-11 11:41:18 +03:00
commit 2d7ac981ba
22 changed files with 150 additions and 313 deletions

1
.npmrc
View File

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

2
.nvmrc
View File

@ -1 +1 @@
16
20

View File

@ -32,7 +32,7 @@
"crypto-js/hmac-sha256",
"crypto-js/enc-base64",
"flat",
"quill"
"quill-delta"
],
"assets": [
"src/favicon-16x16.png",
@ -90,10 +90,10 @@
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"browserTarget": "fuse:build:production"
"buildTarget": "fuse:build:production"
},
"development": {
"browserTarget": "fuse:build:development"
"buildTarget": "fuse:build:development"
}
},
"defaultConfiguration": "development"
@ -101,7 +101,7 @@
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "fuse:build"
"buildTarget": "fuse:build"
}
},
"test": {

View File

@ -1,6 +1,6 @@
{
"name": "fuse-angular",
"version": "18.0.0",
"version": "19.1.0",
"description": "Fuse - Angular Admin Template and Starter Project",
"author": "https://themeforest.net/user/srcn",
"license": "https://themeforest.net/licenses/standard",
@ -13,54 +13,53 @@
"test": "ng test"
},
"dependencies": {
"@angular/animations": "16.0.3",
"@angular/cdk": "16.0.2",
"@angular/common": "16.0.3",
"@angular/compiler": "16.0.3",
"@angular/core": "16.0.3",
"@angular/forms": "16.0.3",
"@angular/material": "16.0.2",
"@angular/material-luxon-adapter": "16.0.2",
"@angular/platform-browser": "16.0.3",
"@angular/platform-browser-dynamic": "16.0.3",
"@angular/router": "16.0.3",
"@ngneat/transloco": "4.2.7",
"apexcharts": "3.40.0",
"crypto-js": "3.3.0",
"highlight.js": "11.8.0",
"@angular/animations": "17.2.4",
"@angular/cdk": "17.2.2",
"@angular/common": "17.2.4",
"@angular/compiler": "17.2.4",
"@angular/core": "17.2.4",
"@angular/forms": "17.2.4",
"@angular/material": "17.2.2",
"@angular/material-luxon-adapter": "17.2.2",
"@angular/platform-browser": "17.2.4",
"@angular/platform-browser-dynamic": "17.2.4",
"@angular/router": "17.2.4",
"@ngneat/transloco": "6.0.4",
"apexcharts": "3.47.0",
"crypto-js": "4.2.0",
"highlight.js": "11.9.0",
"lodash-es": "4.17.21",
"luxon": "3.3.0",
"ng-apexcharts": "1.7.6",
"ngx-quill": "22.0.0",
"luxon": "3.4.4",
"ng-apexcharts": "1.9.0",
"ngx-quill": "25.1.1",
"perfect-scrollbar": "1.5.5",
"quill": "1.3.7",
"rxjs": "7.8.1",
"tslib": "2.5.2",
"zone.js": "0.13.0"
"tslib": "2.6.2",
"zone.js": "0.14.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "16.0.3",
"@angular/cli": "16.0.3",
"@angular/compiler-cli": "16.0.3",
"@tailwindcss/typography": "0.5.9",
"@types/chroma-js": "2.4.0",
"@types/crypto-js": "3.1.47",
"@angular-devkit/build-angular": "17.2.3",
"@angular/cli": "17.2.3",
"@angular/compiler-cli": "17.2.4",
"@tailwindcss/typography": "0.5.10",
"@types/chroma-js": "2.4.4",
"@types/crypto-js": "4.2.2",
"@types/highlight.js": "10.1.0",
"@types/jasmine": "4.3.2",
"@types/lodash": "4.14.195",
"@types/lodash-es": "4.17.7",
"@types/luxon": "3.3.0",
"autoprefixer": "10.4.14",
"@types/jasmine": "5.1.4",
"@types/lodash": "4.14.202",
"@types/lodash-es": "4.17.12",
"@types/luxon": "3.4.2",
"autoprefixer": "10.4.18",
"chroma-js": "2.4.2",
"jasmine-core": "5.0.0",
"karma": "6.4.2",
"jasmine-core": "5.1.2",
"karma": "6.4.3",
"karma-chrome-launcher": "3.2.0",
"karma-coverage": "2.2.0",
"karma-coverage": "2.2.1",
"karma-jasmine": "5.1.0",
"karma-jasmine-html-reporter": "2.0.0",
"karma-jasmine-html-reporter": "2.1.0",
"lodash": "4.17.21",
"postcss": "8.4.24",
"tailwindcss": "3.3.2",
"typescript": "5.0.4"
"postcss": "8.4.35",
"tailwindcss": "3.4.1",
"typescript": "5.3.3"
}
}

View File

@ -1,46 +1,27 @@
import { DOCUMENT, NgTemplateOutlet } from '@angular/common';
import { ChangeDetectionStrategy, Component, Inject, Input, OnInit, TemplateRef, ViewEncapsulation } from '@angular/core';
import { ChangeDetectionStrategy, Component, Inject, Input, TemplateRef, ViewEncapsulation } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatTooltipModule } from '@angular/material/tooltip';
import { FSDocument, FSDocumentElement } from '@fuse/components/fullscreen/fullscreen.types';
@Component({
selector : 'fuse-fullscreen',
templateUrl : './fullscreen.component.html',
encapsulation : ViewEncapsulation.None,
selector: 'fuse-fullscreen',
templateUrl: './fullscreen.component.html',
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
exportAs : 'fuseFullscreen',
standalone : true,
imports : [MatButtonModule, MatTooltipModule, NgTemplateOutlet, MatIconModule],
exportAs: 'fuseFullscreen',
standalone: true,
imports: [MatButtonModule, MatTooltipModule, NgTemplateOutlet, MatIconModule],
})
export class FuseFullscreenComponent implements OnInit
export class FuseFullscreenComponent
{
@Input() iconTpl: TemplateRef<any>;
@Input() tooltip: string;
private _fsDoc: FSDocument;
private _fsDocEl: FSDocumentElement;
private _isFullscreen: boolean = false;
/**
* Constructor
*/
constructor(@Inject(DOCUMENT) private _document: Document)
{
this._fsDoc = _document as FSDocument;
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void
{
this._fsDocEl = document.documentElement as FSDocumentElement;
}
constructor(@Inject(DOCUMENT) private _document: Document) { }
// -----------------------------------------------------------------------------------------------------
// @ Public methods
@ -51,121 +32,27 @@ export class FuseFullscreenComponent implements OnInit
*/
toggleFullscreen(): void
{
// Check if the fullscreen is open
this._isFullscreen = this._getBrowserFullscreenElement() !== null;
if (!this._document.fullscreenEnabled)
{
console.log('Fullscreen is not available in this browser.');
return;
}
// Check if the fullscreen is already open
const fullScreen = this._document.fullscreenElement;
// Toggle the fullscreen
if ( this._isFullscreen )
if (fullScreen)
{
this._closeFullscreen();
this._document.exitFullscreen();
}
else
{
this._openFullscreen();
}
}
// -----------------------------------------------------------------------------------------------------
// @ Private methods
// -----------------------------------------------------------------------------------------------------
/**
* Get browser's fullscreen element
*
* @private
*/
private _getBrowserFullscreenElement(): Element
{
if ( typeof this._fsDoc.fullscreenElement !== 'undefined' )
{
return this._fsDoc.fullscreenElement;
}
if ( typeof this._fsDoc.mozFullScreenElement !== 'undefined' )
{
return this._fsDoc.mozFullScreenElement;
}
if ( typeof this._fsDoc.msFullscreenElement !== 'undefined' )
{
return this._fsDoc.msFullscreenElement;
}
if ( typeof this._fsDoc.webkitFullscreenElement !== 'undefined' )
{
return this._fsDoc.webkitFullscreenElement;
}
throw new Error('Fullscreen mode is not supported by this browser');
}
/**
* Open the fullscreen
*
* @private
*/
private _openFullscreen(): void
{
if ( this._fsDocEl.requestFullscreen )
{
this._fsDocEl.requestFullscreen();
return;
}
// Firefox
if ( this._fsDocEl.mozRequestFullScreen )
{
this._fsDocEl.mozRequestFullScreen();
return;
}
// Chrome, Safari and Opera
if ( this._fsDocEl.webkitRequestFullscreen )
{
this._fsDocEl.webkitRequestFullscreen();
return;
}
// IE/Edge
if ( this._fsDocEl.msRequestFullscreen )
{
this._fsDocEl.msRequestFullscreen();
return;
}
}
/**
* Close the fullscreen
*
* @private
*/
private _closeFullscreen(): void
{
if ( this._fsDoc.exitFullscreen )
{
this._fsDoc.exitFullscreen();
return;
}
// Firefox
if ( this._fsDoc.mozCancelFullScreen )
{
this._fsDoc.mozCancelFullScreen();
return;
}
// Chrome, Safari and Opera
if ( this._fsDoc.webkitExitFullscreen )
{
this._fsDoc.webkitExitFullscreen();
return;
}
// IE/Edge
else if ( this._fsDoc.msExitFullscreen )
{
this._fsDoc.msExitFullscreen();
return;
this._document.documentElement.requestFullscreen()
.catch(() =>
{
console.error('Entering fullscreen mode failed.');
});
}
}
}

View File

@ -1,16 +0,0 @@
export interface FSDocument extends HTMLDocument
{
mozFullScreenElement?: Element;
mozCancelFullScreen?: () => void;
msFullscreenElement?: Element;
msExitFullscreen?: () => void;
webkitFullscreenElement?: Element;
webkitExitFullscreen?: () => void;
}
export interface FSDocumentElement extends HTMLElement
{
mozRequestFullScreen?: () => void;
msRequestFullscreen?: () => void;
webkitRequestFullscreen?: () => void;
}

View File

@ -1,2 +1 @@
export * from '@fuse/components/fullscreen/fullscreen.component';
export * from '@fuse/components/fullscreen/fullscreen.types';

View File

@ -19,20 +19,22 @@ textarea {
@apply text-hint;
}
&:-webkit-autofill {
transition: background-color 600000s 0s, color 600000s 0s !important;
}
&:-webkit-autofill:hover {
transition: background-color 600000s 0s, color 600000s 0s !important;
}
&:-webkit-autofill:focus {
transition: background-color 600000s 0s, color 600000s 0s !important;
}
/* Autofill color fix */
&:-webkit-autofill,
&:-webkit-autofill:hover,
&:-webkit-autofill:focus,
&:-webkit-autofill:active {
transition: background-color 600000s 0s, color 600000s 0s !important;
-webkit-background-clip: text;
transition: background-color 5000s !important;
}
.dark & {
&:-webkit-autofill,
&:-webkit-autofill:hover,
&:-webkit-autofill:focus,
&:-webkit-autofill:active {
-webkit-text-fill-color: rgba(255, 255, 255, 0.87);
}
}
[data-autocompleted] {

View File

@ -1192,6 +1192,21 @@
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* @ Snack bar
/* -------------------------------------------------------------------------- */
.mat-mdc-snack-bar-container {
.mat-mdc-button.mat-mdc-snack-bar-action:not(:disabled) {
color: #FFFFFF !important;
.dark & {
color: #000000 !important;
}
}
}
/* -------------------------------------------------------------------------- */
/* @ Stepper
/* -------------------------------------------------------------------------- */

View File

@ -121,7 +121,7 @@
}
/* Set the foreground color for disabled elements */
[disabled] * {
[disabled] {
@apply text-disabled #{'!important'};
}

View File

@ -1,3 +1,3 @@
import { Version } from '@fuse/version/version';
export const FUSE_VERSION = new Version('18.0.0').full;
export const FUSE_VERSION = new Version('19.1.0').full;

View File

@ -1,15 +1,17 @@
import { provideHttpClient } from '@angular/common/http';
import { ApplicationConfig } from '@angular/core';
import { APP_INITIALIZER, ApplicationConfig, inject } from '@angular/core';
import { LuxonDateAdapter } from '@angular/material-luxon-adapter';
import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core';
import { provideAnimations } from '@angular/platform-browser/animations';
import { PreloadAllModules, provideRouter, withInMemoryScrolling, withPreloading } from '@angular/router';
import { provideFuse } from '@fuse';
import { provideTransloco, TranslocoService } from '@ngneat/transloco';
import { firstValueFrom } from 'rxjs';
import { appRoutes } from 'app/app.routes';
import { provideAuth } from 'app/core/auth/auth.provider';
import { provideIcons } from 'app/core/icons/icons.provider';
import { provideTransloco } from 'app/core/transloco/transloco.provider';
import { mockApiServices } from 'app/mock-api';
import { TranslocoHttpLoader } from './core/transloco/transloco.http-loader';
export const appConfig: ApplicationConfig = {
providers: [
@ -41,7 +43,38 @@ export const appConfig: ApplicationConfig = {
},
// Transloco Config
provideTransloco(),
provideTransloco({
config: {
availableLangs : [
{
id : 'en',
label: 'English',
},
{
id : 'tr',
label: 'Turkish',
},
],
defaultLang : 'en',
fallbackLang : 'en',
reRenderOnLangChange: true,
prodMode : true,
},
loader: TranslocoHttpLoader,
}),
{
// Preload the default language before the app starts to prevent empty/jumping content
provide : APP_INITIALIZER,
useFactory: () =>
{
const translocoService = inject(TranslocoService);
const defaultLang = translocoService.getDefaultLang();
translocoService.setActiveLang(defaultLang);
return () => firstValueFrom(translocoService.load(defaultLang));
},
multi : true,
},
// Fuse
provideAuth(),

View File

@ -1,5 +1,5 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { inject, Injectable } from '@angular/core';
import { AuthUtils } from 'app/core/auth/auth.utils';
import { UserService } from 'app/core/user/user.service';
import { catchError, Observable, of, switchMap, throwError } from 'rxjs';
@ -8,16 +8,8 @@ import { catchError, Observable, of, switchMap, throwError } from 'rxjs';
export class AuthService
{
private _authenticated: boolean = false;
/**
* Constructor
*/
constructor(
private _httpClient: HttpClient,
private _userService: UserService,
)
{
}
private _httpClient = inject(HttpClient);
private _userService = inject(UserService);
// -----------------------------------------------------------------------------------------------------
// @ Accessors

View File

@ -7,13 +7,6 @@
export class AuthUtils
{
/**
* Constructor
*/
constructor()
{
}
// -----------------------------------------------------------------------------------------------------
// @ Public methods
// -----------------------------------------------------------------------------------------------------

View File

@ -1,20 +1,14 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { inject, Injectable } from '@angular/core';
import { Navigation } from 'app/core/navigation/navigation.types';
import { Observable, ReplaySubject, tap } from 'rxjs';
@Injectable({providedIn: 'root'})
export class NavigationService
{
private _httpClient = inject(HttpClient);
private _navigation: ReplaySubject<Navigation> = new ReplaySubject<Navigation>(1);
/**
* Constructor
*/
constructor(private _httpClient: HttpClient)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------

View File

@ -1,18 +1,12 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { inject, Injectable } from '@angular/core';
import { Translation, TranslocoLoader } from '@ngneat/transloco';
import { Observable } from 'rxjs';
@Injectable({providedIn: 'root'})
export class TranslocoHttpLoader implements TranslocoLoader
{
/**
* Constructor
*/
constructor(
private _httpClient: HttpClient)
{
}
private _httpClient = inject(HttpClient);
// -----------------------------------------------------------------------------------------------------
// @ Public methods

View File

@ -1,48 +0,0 @@
import { APP_INITIALIZER, EnvironmentProviders, importProvidersFrom, inject, Provider } from '@angular/core';
import { TRANSLOCO_CONFIG, TRANSLOCO_LOADER, translocoConfig, TranslocoModule, TranslocoService } from '@ngneat/transloco';
import { TranslocoHttpLoader } from 'app/core/transloco/transloco.http-loader';
export const provideTransloco = (): Array<Provider | EnvironmentProviders> =>
{
return [
importProvidersFrom(TranslocoModule),
{
// Provide the default Transloco configuration
provide : TRANSLOCO_CONFIG,
useValue: translocoConfig({
availableLangs : [
{
id : 'en',
label: 'English',
},
{
id : 'tr',
label: 'Turkish',
},
],
defaultLang : 'en',
fallbackLang : 'en',
reRenderOnLangChange: true,
prodMode : true,
}),
},
{
// Provide the default Transloco loader
provide : TRANSLOCO_LOADER,
useClass: TranslocoHttpLoader,
},
{
// Preload the default language before the app starts to prevent empty/jumping content
provide : APP_INITIALIZER,
useFactory: () =>
{
const translocoService = inject(TranslocoService);
const defaultLang = translocoService.getDefaultLang();
translocoService.setActiveLang(defaultLang);
return () => translocoService.load(defaultLang).toPromise();
},
multi : true,
},
];
};

View File

@ -1,20 +1,14 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { inject, Injectable } from '@angular/core';
import { User } from 'app/core/user/user.types';
import { map, Observable, ReplaySubject, tap } from 'rxjs';
@Injectable({providedIn: 'root'})
export class UserService
{
private _httpClient = inject(HttpClient);
private _user: ReplaySubject<User> = new ReplaySubject<User>(1);
/**
* Constructor
*/
constructor(private _httpClient: HttpClient)
{
}
// -----------------------------------------------------------------------------------------------------
// @ Accessors
// -----------------------------------------------------------------------------------------------------
@ -40,7 +34,7 @@ export class UserService
// -----------------------------------------------------------------------------------------------------
/**
* Get the current logged in user data
* Get the current signed-in user data
*/
get(): Observable<User>
{

View File

@ -32,6 +32,7 @@
<div class="text-lg font-medium leading-10">Messages</div>
<div class="ml-auto">
<button
class="dark:text-white"
mat-icon-button
[disabled]="unreadCount === 0"
[matTooltip]="'Mark all as read'"

View File

@ -32,6 +32,7 @@
<div class="text-lg font-medium leading-10">Notifications</div>
<div class="ml-auto">
<button
class="dark:text-white"
mat-icon-button
[matTooltip]="'Mark all as read'"
[disabled]="unreadCount === 0"

View File

@ -162,9 +162,7 @@
<div class="flex items-center h-11 my-px ml-4">
<button
mat-icon-button>
<mat-icon
class="rotate-90"
[svgIcon]="'heroicons_outline:paper-airplane'"></mat-icon>
<mat-icon [svgIcon]="'heroicons_outline:paper-airplane'"></mat-icon>
</button>
</div>
</div>

View File

@ -27,7 +27,7 @@
{{user.name}}
</div>
<div class="w-full mt-0.5 whitespace-nowrap text-sm text-ellipsis overflow-hidden leading-normal text-current opacity-50">
brian.hughes@company.com
brian.hughes&#64;company.com
</div>
</div>
</div>