ADDED Materialize theme

This commit is contained in:
Marek Lesko
2025-10-13 18:18:04 +02:00
parent 9451589a9d
commit 4dda50cbf4
1669 changed files with 146258 additions and 1 deletions

15
theme/docs/index.html Normal file
View File

@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<title>Modernize Angular Premium Template | Docs</title>
<meta http-equiv="refresh"
content="0; URL = 'https://adminmart.github.io/premium-documentation/angular/modernize/index.html'" />
</head>
<body>
<h1>Modernize Angular Premium Template</h1>
<a href="https://adminmart.github.io/premium-documentation/angular/modernize/index.html">https://adminmart.github.io/premium-documentation/angular/modernize/index.html</a>
</body>
</html>

View File

@@ -0,0 +1 @@
https://www.figma.com/file/vx7BDKIRGoSwxs5lItTMlD/Modernize

14283
theme/packages/authguard/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,46 @@
{
"name": "modernize",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test"
},
"private": true,
"dependencies": {
"@angular/animations": "^20.0.4",
"@angular/cdk": "^20.0.3",
"@angular/common": "^20.0.4",
"@angular/compiler": "^20.0.4",
"@angular/core": "^20.0.4",
"@angular/forms": "^20.0.4",
"@angular/material": "^20.0.3",
"@angular/platform-browser": "^20.0.4",
"@angular/platform-browser-dynamic": "^20.0.4",
"@angular/router": "^20.0.4",
"@ngx-translate/core": "^14.0.0",
"@ngx-translate/http-loader": "^7.0.0",
"angular-tabler-icons": "^3.26.0",
"ngx-scrollbar": "^18.0.0",
"rxjs": "~7.8.2",
"sass": "^1.89.2",
"tslib": "^2.8.1",
"zone.js": "~0.15.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "^20.0.3",
"@angular/cli": "~20.0.3",
"@angular/compiler-cli": "^20.0.4",
"@types/date-fns": "^2.6.3",
"@types/jasmine": "~5.1.8",
"jasmine-core": "~5.8.0",
"karma": "~6.4.4",
"karma-chrome-launcher": "~3.2.0",
"karma-coverage": "~2.2.1",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.1.0",
"typescript": "~5.8.3"
}
}

View File

@@ -0,0 +1,35 @@
import { TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [
AppComponent
],
}).compileComponents();
});
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
it(`should have as title 'Angular20'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual('Angular20');
});
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelector('.content span')?.textContent).toContain('Angular20 app is running!');
});
});

View File

@@ -0,0 +1,190 @@
<mat-sidenav-container class="mainWrapper" autosize autoFocus [ngClass]="{
'sidebarNav-mini': options.sidenavCollapsed && options.navPos !== 'top' && !resView,
'sidebarNav-horizontal': options.horizontal,
cardBorder: options.cardBorder,
}" [dir]="options.dir!">
<!-- ============================================================== -->
<!-- Vertical Sidebar -->
<!-- ============================================================== -->
@if (!options.horizontal) {
<mat-sidenav #leftsidenav [mode]="isOver ? 'over' : 'side'" [opened]="
options.navPos === 'side' && options.sidenavOpened && !isOver && !resView
" (openedChange)="onSidenavOpenedChange($event)" (closedStart)="onSidenavClosedStart()" class="sidebarNav">
<div class="flex-layout">
<app-sidebar (toggleMobileNav)="sidenav.toggle()" [showToggle]="isOver"></app-sidebar>
<ng-scrollbar class="position-relative" style="height: 100%">
<mat-nav-list class="sidebar-list">
@for(item of navItems; track item) {
<app-nav-item [item]="item" (notify)="sidenav.toggle()" class="top-parent">
</app-nav-item>
}
</mat-nav-list>
</ng-scrollbar>
<div class="p-24 m-t-auto profile-bar">
<div class="bg-light-secondary d-flex align-items-center rounded p-16">
<img src="/assets/images/profile/user-1.jpg" class="rounded-circle" width="40" />
<div class="m-l-16">
<h4 class="f-w-600">Mathew</h4>
<span class="f-s-12">Designer</span>
</div>
<div class="m-l-auto">
<a mat-icon-button [routerLink]="['/authentication/login']" class="d-flex justify-content-center">
<i-tabler name="power" class="text-primary icon-18 d-flex"></i-tabler>
</a>
</div>
</div>
</div>
</div>
</mat-sidenav>
}
<!-- ============================================================== -->
<!-- horizontal Sidebar -->
<!-- ============================================================== -->
@if (resView) {
<mat-sidenav #leftsidenav [mode]="'over'" [opened]="options.sidenavOpened && !isTablet"
(openedChange)="onSidenavOpenedChange($event)" (closedStart)="onSidenavClosedStart()" class="sidebarNav">
<app-sidebar> </app-sidebar>
<ng-scrollbar class="position-relative" style="height: 100%">
<mat-nav-list class="sidebar-list">
@for(item of navItems; track item) {
<app-nav-item [item]="item" (notify)="sidenav.toggle()"> </app-nav-item>
}
</mat-nav-list>
</ng-scrollbar>
<div class="p-24 m-t-auto profile-bar">
<div class="bg-light-secondary d-flex align-items-center rounded p-16">
<img src="/assets/images/profile/user-1.jpg" class="rounded-circle" width="40" />
<div class="m-l-16">
<h4 class="f-w-600">Mathew</h4>
<span class="f-s-12">Designer</span>
</div>
<div class="m-l-auto">
<a mat-icon-button [routerLink]="['/authentication/login']" class="d-flex justify-content-center">
<i-tabler name="power" class="text-primary icon-18 d-flex"></i-tabler>
</a>
</div>
</div>
</div>
</mat-sidenav>
}
<!-- ============================================================== -->
<!-- Main Content -->
<!-- ============================================================== -->
<mat-sidenav-content class="contentWrapper" #content>
<!-- ============================================================== -->
<!-- VerticalHeader -->
<!-- ============================================================== -->
@if (!options.horizontal) {
<app-header [showToggle]="!isOver" (toggleCollapsed)="toggleCollapsed()" (toggleMobileNav)="sidenav.toggle()"
(toggleMobileFilterNav)="toggleFilterNav()" (optionsChange)="receiveOptions($event)"></app-header>
} @else {
<!-- horizontal header -->
<app-horizontal-header (toggleMobileNav)="sidenav.toggle()" (toggleMobileFilterNav)="toggleFilterNav()"
(optionsChange)="receiveOptions($event)"></app-horizontal-header>
} @if(options.horizontal) {
<app-horizontal-sidebar></app-horizontal-sidebar>
}
<main class="pageWrapper" [ngClass]="{
maxWidth: options.boxed
}">
<app-breadcrumb></app-breadcrumb>
<!-- ============================================================== -->
<!-- Outlet -->
<!-- ============================================================== -->
<router-outlet></router-outlet>
<div class="customizerBtn">
<button mat-fab class="bg-primary text-white" (click)="customizerRight.toggle()">
<mat-icon>settings</mat-icon>
</button>
</div>
</main>
<!-- ------------------------------------------------------------------
Mobile Apps Sidebar
------------------------------------------------------------------ -->
<div [class.open]="isFilterNavOpen" class="filter-sidebar">
<div>
<div class="d-flex justify-content-between align-items-center">
<div class="branding">
@if(options.theme === 'light') {
<a href="/">
<img src="./assets/images/logos/dark-logo.svg" class="align-middle m-2" alt="logo" />
</a>
} @else {
<a href="/">
<img src="./assets/images/logos/light-logo.svg" class="align-middle m-2" alt="logo" />
</a>
}
</div>
<button mat-icon-button (click)="isFilterNavOpen = !isFilterNavOpen" class="d-flex justify-content-center">
<i-tabler name="x" class="icon-18 d-flex"></i-tabler>
</button>
</div>
<mat-accordion>
<mat-expansion-panel class="shadow-none">
<mat-expansion-panel-header>
<mat-panel-title class="f-s-16 f-w-500"> Apps </mat-panel-title>
</mat-expansion-panel-header>
<div>
<div class="row">
@for(appdd of apps; track appdd.img) {
<div class="col-12 text-hover-primary">
<a [routerLink]="[appdd.link]" class="d-flex align-items-center text-decoration-none m-b-24 gap-16">
<button mat-mini-fab class="text-primary bg-light-primary shadow-none rounded">
<img [src]="appdd.img" width="20" />
</button>
<div>
<h5 class="f-s-14 f-w-600 m-0 textprimary f-s-14 hover-text">
{{ appdd.title }}
</h5>
<span class="f-s-14 f-s-12">{{ appdd.subtitle }}</span>
</div>
</a>
</div>
}
</div>
<h4 class="f-s-18 f-w-600 m-b-16">Quick Links</h4>
@for(quicklink of quicklinks; track quicklink.title) {
<div class="text-hover-primary">
<a [routerLink]="['quicklink.link']"
class="hover-text text-decoration-none f-s-14 f-w-600 d-block p-y-8">{{ quicklink.title }}</a>
</div>
}
</div>
</mat-expansion-panel>
</mat-accordion>
<div class="p-x-16">
<a [routerLink]="['/']" class="d-flex align-items-center text-decoration-none f-s-14 p-y-16 gap-8">
<span class="f-s-15 f-w-500 m-l-8">Calendar</span>
</a>
<a [routerLink]="['/']" class="d-flex align-items-center text-decoration-none f-s-14 p-y-16">
<span class="f-s-15 f-w-500 m-l-8">Chat</span>
</a>
<a [routerLink]="['/']" class="d-flex align-items-center text-decoration-none f-s-14 p-y-16 gap-8">
<span class="f-s-15 f-w-500 m-l-8">Email</span>
</a>
</div>
</div>
</div>
</mat-sidenav-content>
<mat-sidenav #customizerRight mode="over" position="end" class="customizerNav">
<div class="p-x-16 p-y-20 d-flex align-items-center justify-content-between b-b-1">
<h3 class="f-s-21 f-w-600">Settings</h3>
<a mat-icon-button (click)="customizerRight.toggle()" class="d-flex justify-content-center">
<mat-icon>close</mat-icon>
</a>
</div>
<app-customizer (optionsChange)="receiveOptions($event)"></app-customizer>
</mat-sidenav>
</mat-sidenav-container>

View File

@@ -0,0 +1,296 @@
<mat-toolbar class="topbar horizontal-topbar ">
<div class="container">
<div class="d-none d-sm-flex">
<app-branding></app-branding>
</div>
<!-- Mobile Menu -->
<button
mat-icon-button
(click)="toggleMobileNav.emit()"
class="d-flex align-items-center justify-content-center d-lg-none m-x-4"
>
<i-tabler name="menu-2" class="icon-20 d-flex"></i-tabler>
</button>
<!-- --------------------------------------------------------------- -->
<!-- --------------------------------------------------------------- -->
<!-- Search -->
<!-- --------------------------------------------------------------- -->
<button mat-icon-button (click)="openDialog()" class="d-flex align-items-center justify-content-center m-x-4">
<i-tabler name="search" class="icon-20 d-flex"></i-tabler>
</button>
<div class="d-none d-lg-flex">
<!-- --------------------------------------------------------------- -->
<!-- Links -->
<!-- --------------------------------------------------------------- -->
<button
mat-button
[matMenuTriggerFor]="appsmenu"
aria-label="Notifications"
>
<div class="d-flex align-items-center">
Apps <i-tabler name="chevron-down" class="icon-16 m-l-4"></i-tabler>
</div>
</button>
<mat-menu #appsmenu="matMenu" class="apps-dd cardWithShadow">
<div class="row">
<div class="col-sm-8 b-r-1 p-r-0">
<div class="p-32 p-b-0">
<div class="row">
@for(appdd of apps; track appdd.title) {
<div class="col-sm-6 text-hover-primary">
<a
[routerLink]="[appdd.link]"
class="d-flex align-items-center text-decoration-none m-b-24"
>
<span
class="text-primary bg-light rounded icon-40 d-flex align-items-center justify-content-center"
>
<img [src]="appdd.img" width="20" />
</span>
<div class="m-l-16">
<h5
class="f-s-14 f-w-600 m-0 textprimary hover-text"
>
{{ appdd.title }}
</h5>
<span class=" f-s-12">{{
appdd.subtitle
}}</span>
</div>
</a>
</div>
}
</div>
</div>
<div
class="b-t-1 p-24 d-none d-lg-flex align-items-center justify-content-between"
>
<span
class="d-flex align-items-center f-s-16 f-w-500"
>
<i-tabler name="help" class="icon-20 m-r-8"></i-tabler
>Frequently Asked Questions
</span>
<a
[routerLink]="['/theme-pages/faq']"
mat-flat-button
color="primary"
>Check</a
>
</div>
</div>
<div class="col-sm-4">
<div class="p-x-16 p-y-32">
<h4 class="f-s-18 f-w-600 m-b-16">Quick Links</h4>
@for(quicklink of quicklinks; track quicklink.title) {
<div class="text-hover-primary">
<a
[routerLink]="[quicklink.link]"
class="hover-text text-decoration-none f-w-600 d-block p-y-8"
>{{ quicklink.title }}</a
>
</div>
}
</div>
</div>
</div>
</mat-menu>
<a mat-button [routerLink]="['/']">Chat</a>
<a mat-button [routerLink]="['/']">Calendar</a>
<a mat-button [routerLink]="['/']">Email</a>
</div>
<span class="flex-1-auto"></span>
<!-- Mobile Menu -->
<button
mat-icon-button
(click)="toggleMobileFilterNav.emit()"
class="d-flex d-lg-none justify-content-center m-x-4"
>
<i-tabler name="grid-dots" class="icon-20 d-flex"></i-tabler>
</button>
<!-- --------------------------------------------------------------- -->
<!-- langugage Dropdown -->
<!-- --------------------------------------------------------------- -->
<button [matMenuTriggerFor]="flags" mat-icon-button class="m-x-4">
<img
[src]="selectedLanguage.icon"
class="rounded-circle object-cover icon-20"
/>
</button>
<mat-menu #flags="matMenu" class="cardWithShadow">
@for(lang of languages; track lang.icon) {
<button mat-menu-item (click)="changeLanguage(lang)">
<div class="d-flex align-items-center">
<img
[src]="lang.icon"
class="rounded-circle object-cover m-r-8 icon-20"
/>
<span class=" f-s-14">{{ lang.language }}</span>
</div>
</button>
}
</mat-menu>
@if(options.theme=='light'){
<button mat-icon-button aria-label="lightdark" class="d-flex justify-content-center" (click)="setlightDark('dark')" >
<i-tabler class="d-flex icon-22" [name]="'moon'"></i-tabler>
</button>
}@else{
<button mat-icon-button aria-label="lightdark" class="d-flex justify-content-center" (click)="setlightDark('light')">
<i-tabler class="d-flex icon-22" [name]="'sun'"></i-tabler>
</button>
}
<!-- --------------------------------------------------------------- -->
<!-- Notification Dropdown -->
<!-- --------------------------------------------------------------- -->
<button
mat-icon-button matBadge="5"
[matMenuTriggerFor]="notificationmenu"
aria-label="Notifications" class="m-x-4 notification-badge"
>
<i-tabler
class="d-flex"
name="bell"
></i-tabler>
</button>
<mat-menu
#notificationmenu="matMenu"
xPosition="before"
class="topbar-dd cardWithShadow"
>
<div class="d-flex align-items-center p-x-32 p-y-16">
<h6 class="f-s-16 f-w-600 m-0 ">Notifications</h6>
<span class="m-l-auto">
<span class="bg-primary text-white p-x-8 p-y-4 f-w-500 rounded f-s-12"
>5 new</span
>
</span>
</div>
@for(notification of notifications; track notification.title) {
<button mat-menu-item class="p-x-32 p-y-16">
<div class="d-flex align-items-center">
<img [src]="notification.img" class="rounded-circle" width="48" />
<div class="m-l-16">
<h5 class="f-s-14 f-w-600 m-0 ">
{{ notification.title }}
</h5>
<span>{{ notification.subtitle }}</span>
</div>
</div>
</button>
}
<div class="p-y-12 p-x-32">
<button mat-stroked-button color="primary" class="w-100">
See all notifications
</button>
</div>
</mat-menu>
<!-- --------------------------------------------------------------- -->
<!-- profile Dropdown -->
<!-- --------------------------------------------------------------- -->
<button
mat-icon-button
[matMenuTriggerFor]="profilemenu"
aria-label="Notifications" class="m-l-4"
>
<img
src="/assets/images/profile/user-1.jpg"
class="rounded-circle object-cover icon-35 profile-dd"
width="35"
/>
</button>
<mat-menu
#profilemenu="matMenu"
xPosition="before"
class="topbar-dd cardWithShadow"
>
<div class="p-x-32 p-y-16">
<h6 class="f-s-16 f-w-600 m-0 ">User Profile</h6>
<div class="d-flex align-items-center p-b-24 b-b-1 m-t-16">
<img
src="/assets/images/profile/user-1.jpg"
class="rounded-circle"
width="95"
/>
<div class="m-l-16">
<h6 class="f-s-14 f-w-600 m-0 ">Mathew Anderson</h6>
<span class="f-s-14 d-block m-b-4">Designer</span>
<span class="d-flex align-items-center">
<i-tabler name="mail" class="icon-15 m-r-4"></i-tabler>
info&#64;modernize.com
</span>
</div>
</div>
</div>
<div class="p-x-32">
@for(profile of profiledd; track profile.title) {
<a
class="p-y-16 text-decoration-none d-block text-hover-primary"
[routerLink]="[profile.link]"
>
<div class="d-flex align-items-center">
<button
mat-mini-fab
class="text-primary bg-light shadow-none rounded"
>
<img [src]="profile.img" width="20" />
</button>
<div class="m-l-16">
<h5
class="f-s-14 f-w-600 m-0 textprimary hover-text"
>
{{ profile.title }}
</h5>
<span class="">{{ profile.subtitle }}</span>
</div>
</div>
</a>
}
<!-- upgrade -->
<div
class="p-24 overflow-hidden bg-light-primary rounded position-relative m-y-16"
>
<div class="d-flex align-items-center">
<div>
<h5 class="f-s-18 m-0 f-w-600 m-b-12 ">
Unlimited <br />
Access
</h5>
<button mat-flat-button color="primary">Upgrade</button>
</div>
<div class="m-l-auto">
<img
src="/assets/images/backgrounds/unlimited-bg.png"
alt="upgrade-bg"
class="upgrade-bg"
/>
</div>
</div>
</div>
</div>
<div class="p-y-12 p-x-32">
<a
[routerLink]="['/authentication/login']"
mat-stroked-button
color="primary"
class="w-100"
>Logout</a
>
</div>
</mat-menu>
</div>
</mat-toolbar>

View File

@@ -0,0 +1,43 @@
import { Component, OnInit } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { RouterModule } from '@angular/router';
import { Router, NavigationEnd, ActivatedRoute, Data } from '@angular/router';
import { filter, map, mergeMap } from 'rxjs/operators';
import { TablerIconsModule } from 'angular-tabler-icons';
@Component({
selector: 'app-breadcrumb',
imports: [RouterModule, TablerIconsModule],
templateUrl: './breadcrumb.component.html',
styleUrls: [],
})
export class AppBreadcrumbComponent {
// @Input() layout;
pageInfo: Data | any = Object.create(null);
myurl: any = this.router.url.slice(1).split('/');
constructor(
private router: Router,
private activatedRoute: ActivatedRoute,
private titleService: Title
) {
this.router.events
.pipe(filter((event) => event instanceof NavigationEnd))
.pipe(map(() => this.activatedRoute))
.pipe(
map((route) => {
while (route.firstChild) {
route = route.firstChild;
}
return route;
})
)
.pipe(filter((route) => route.outlet === 'primary'))
.pipe(mergeMap((route) => route.data))
// tslint:disable-next-line - Disables all
.subscribe((event) => {
// tslint:disable-next-line - Disables all
this.titleService.setTitle(event['title'] + ' - Angular 20');
this.pageInfo = event;
});
}
}

View File

@@ -0,0 +1,300 @@
<mat-toolbar class="topbar gap-10">
<!-- --------------------------------------------------------------- -->
<!-- Desktop Menu -->
@if(showToggle) {
<button
mat-icon-button
(click)="toggleCollapsed.emit()"
class="d-flex justify-content-center"
>
<i-tabler name="menu-2" class="icon-20 d-flex"></i-tabler>
</button>
}
<!-- Mobile Menu -->
@if(!showToggle) {
<button
mat-icon-button
(click)="toggleMobileNav.emit()"
class="d-flex justify-content-center"
>
<i-tabler name="menu-2" class="icon-20 d-flex"></i-tabler>
</button>
}
<!-- --------------------------------------------------------------- -->
<!-- --------------------------------------------------------------- -->
<!-- Search -->
<!-- --------------------------------------------------------------- -->
<button
mat-icon-button
(click)="openDialog()"
class="d-flex justify-content-center"
>
<i-tabler name="search" class="icon-20 d-flex"></i-tabler>
</button>
<div class="d-none d-lg-flex">
<!-- --------------------------------------------------------------- -->
<!-- Links -->
<!-- --------------------------------------------------------------- -->
<button
mat-button
[matMenuTriggerFor]="appsmenu"
aria-label="Notifications"
>
<div class="d-flex align-items-center">
Apps <i-tabler name="chevron-down" class="icon-16 m-l-4"></i-tabler>
</div>
</button>
<mat-menu #appsmenu="matMenu" class="apps-dd cardWithShadow">
<div class="row">
<div class="col-sm-8 b-r-1 p-r-0">
<div class="p-32 p-b-0">
<div class="row">
@for(appdd of apps; track appdd.title) {
<div class="col-sm-6 text-hover-primary">
<a
[routerLink]="[appdd.link]"
class="d-flex align-items-center text-decoration-none m-b-24"
>
<span
class="bg-light rounded icon-40 d-flex align-items-center justify-content-center"
>
<img [src]="appdd.img" width="20" />
</span>
<div class="m-l-16">
<h5
class="f-s-14 f-w-600 m-0 hover-text"
>
{{ appdd.title }}
</h5>
<span class=" f-s-12 text-body">{{ appdd.subtitle }}</span>
</div>
</a>
</div>
}
</div>
</div>
<div
class="b-t-1 p-24 d-none d-lg-flex align-items-center justify-content-between"
>
<span
class="d-flex align-items-center f-s-16 f-w-500"
>
<i-tabler name="help" class="icon-20 m-r-8"></i-tabler>Frequently
Asked Questions
</span>
<a
[routerLink]="['/theme-pages/faq']"
mat-flat-button
color="primary"
>Check</a
>
</div>
</div>
<div class="col-sm-4">
<div class="p-x-16 p-y-32">
<h4 class="f-s-18 f-w-600 m-b-16">Quick Links</h4>
@for(quicklink of quicklinks; track quicklink.title) {
<div class="text-hover-primary">
<a
[routerLink]="[quicklink.link]"
class="hover-text text-decoration-none f-w-600 d-block p-y-8"
>{{ quicklink.title }}</a
>
</div>
}
</div>
</div>
</div>
</mat-menu>
<a mat-button [routerLink]="['/apps/chat']">Chat</a>
<a mat-button [routerLink]="['/apps/calendar']">Calendar</a>
<a mat-button [routerLink]="['/apps/email/inbox']">Email</a>
</div>
<span class="flex-1-auto"></span>
<!-- Mobile Menu -->
<button
mat-icon-button
(click)="toggleMobileFilterNav.emit()"
class="d-flex d-lg-none justify-content-center"
>
<i-tabler name="grid-dots" class="icon-20 d-flex"></i-tabler>
</button>
<!-- --------------------------------------------------------------- -->
<!-- langugage Dropdown -->
<!-- --------------------------------------------------------------- -->
<button [matMenuTriggerFor]="flags" mat-icon-button class="m-r-5">
<img
[src]="selectedLanguage.icon"
class="rounded-circle object-cover icon-20"
/>
</button>
<mat-menu #flags="matMenu" class="cardWithShadow">
@for(lang of languages; track lang.icon) {
<button mat-menu-item (click)="changeLanguage(lang)">
<div class="d-flex align-items-center">
<img
[src]="lang.icon"
class="rounded-circle object-cover m-r-8 icon-20"
/>
<span class=" f-s-14">{{ lang.language }}</span>
</div>
</button>
}
</mat-menu>
@if(options.theme=='light'){
<button mat-icon-button aria-label="lightdark" class="d-flex justify-content-center" (click)="setlightDark('dark')" >
<i-tabler class="d-flex icon-22" [name]="'moon'"></i-tabler>
</button>
}@else{
<button mat-icon-button aria-label="lightdark" class="d-flex justify-content-center" (click)="setlightDark('light')">
<i-tabler class="d-flex icon-22" [name]="'sun'"></i-tabler>
</button>
}
<!-- --------------------------------------------------------------- -->
<!-- Notification Dropdown -->
<!-- --------------------------------------------------------------- -->
<button
mat-icon-button matBadge="5"
[matMenuTriggerFor]="notificationmenu"
aria-label="Notifications" class="notification-badge"
>
<i-tabler
class="d-flex"
name="bell"
></i-tabler>
</button>
<mat-menu #notificationmenu="matMenu" class="topbar-dd cardWithShadow">
<div class="d-flex align-items-center p-x-32 p-y-16">
<h6 class="f-s-16 f-w-600 m-0 ">Notifications</h6>
<span class="m-l-auto">
<span class="bg-primary text-white p-x-8 p-y-4 f-w-500 rounded f-s-12"
>5 new</span
>
</span>
</div>
@for(notification of notifications; track notification.title) {
<button mat-menu-item class="p-x-32 p-y-16">
<div class="d-flex align-items-center">
<img [src]="notification.img" class="rounded-circle" width="48" />
<div class="m-l-16">
<h5 class="f-s-14 f-w-600 m-0 ">
{{ notification.title }}
</h5>
<span>{{ notification.subtitle }}</span>
</div>
</div>
</button>
}
<div class="p-y-12 p-x-32">
<button mat-stroked-button color="primary" class="w-100">
See all notifications
</button>
</div>
</mat-menu>
<!-- --------------------------------------------------------------- -->
<!-- profile Dropdown -->
<!-- --------------------------------------------------------------- -->
<button
mat-icon-button
[matMenuTriggerFor]="profilemenu"
aria-label="Notifications"
>
<img
src="/assets/images/profile/user-1.jpg"
class="rounded-circle object-cover icon-35 profile-dd"
width="35"
/>
</button>
<mat-menu #profilemenu="matMenu" class="topbar-dd cardWithShadow">
<ng-scrollbar class="position-relative" style="height: 647px">
<div class="p-x-32 p-y-16">
<h6 class="f-s-16 f-w-600 m-0 ">User Profile</h6>
<div class="d-flex align-items-center p-b-24 b-b-1 m-t-16">
<img
src="/assets/images/profile/user-1.jpg"
class="rounded-circle"
width="95"
/>
<div class="m-l-16">
<h6 class="f-s-14 f-w-600 m-0 ">Mathew Anderson</h6>
<span class="f-s-14 d-block m-b-4">Designer</span>
<span class="d-flex align-items-center">
<i-tabler name="mail" class="icon-15 m-r-4"></i-tabler>
info&#64;modernize.com
</span>
</div>
</div>
</div>
<div class="p-x-32">
@for(profile of profiledd; track profile.title) {
<a
class="p-y-16 text-decoration-none d-block text-hover-primary"
[routerLink]="[profile.link]"
>
<div class="d-flex align-items-center">
<button
mat-mini-fab
class="text-primary bg-light shadow-none rounded"
>
<img [src]="profile.img" width="20" />
</button>
<div class="m-l-16">
<h5
class="f-s-14 f-w-600 m-0 textprimary hover-text"
>
{{ profile.title }}
</h5>
<span class="text-body">{{ profile.subtitle }}</span>
</div>
</div>
</a>
}
<!-- upgrade -->
<div
class="p-24 overflow-hidden bg-light rounded position-relative m-y-16"
>
<div class="d-flex align-items-center">
<div>
<h5 class="f-s-18 m-0 f-w-600 m-b-12 ">
Unlimited <br />
Access
</h5>
<button mat-flat-button color="primary">Upgrade</button>
</div>
<div class="m-l-auto">
<img
src="/assets/images/backgrounds/unlimited-bg.png"
alt="upgrade-bg"
class="upgrade-bg"
/>
</div>
</div>
</div>
</div>
<div class="p-y-12 p-x-32">
<a
[routerLink]="['/authentication/login']"
mat-stroked-button
color="primary"
class="w-100"
>Logout</a
>
</div>
</ng-scrollbar>
</mat-menu>
</mat-toolbar>

View File

@@ -0,0 +1,153 @@
@use "variables" as *;
*,
:after,
:before {
box-sizing: border-box;
}
body {
font-family: $font-family;
line-height: 1.334rem;
overflow-x: hidden;
color: var(--mat-sys-on-background);
}
.mainWrapper {
display: flex;
min-height: 100vh;
width: 100%;
flex: 1;
height: 100%;
}
.container {
max-width: 1200px;
padding-left: 24px;
padding-right: 24px;
margin: 0 auto;
&.full-width {
display: flex;
align-items: center;
width: 100%;
}
}
.pageWrapper {
padding: 24px;
min-height: calc(100vh - 70px);
margin: 0 auto;
&.maxWidth {
max-width: $boxedWidth;
}
}
.w-100 {
width: 100%;
}
.h-100 {
height: 100%;
}
.shadow-none {
box-shadow: none !important;
}
.rounded {
border-radius: $border-radius !important;
}
.rounded-circle {
border-radius: 50% !important;
}
.rounded-pill {
border-radius: 25px !important;
}
.overflow-hidden {
overflow: hidden;
}
.text-decoration-none {
text-decoration: none;
}
.position-relative {
position: relative;
}
.table-responsive {
overflow-x: auto;
td,
mat-cell {
white-space: nowrap;
padding: 16px;
}
}
.op-5 {
opacity: 0.5;
}
.cursor-pointer {
cursor: pointer;
}
.avatar-group {
img {
border: 2px solid $white;
margin-right: -5px;
&:last-child {
margin-right: 0;
}
}
}
a {
color: var(--mat-sys-on-background);
&:hover {
color: $primary;
}
}
.filter-sidebar {
width: 290px;
position: fixed;
right: -290px;
top: 0;
z-index: 10;
height: 100%;
transition: all 0.3s ease-in-out;
box-shadow: var(--mat-sys-level3);
background-color: var(--mat-sys-background);
&.open {
right: 0;
}
}
pre {
margin: 0;
white-space: nowrap;
}
td.hljs-ln-line.hljs-ln-numbers {
padding-right: 10px;
}
@media (min-width: 768px) {
html .flex-sm-row {
flex-direction: row !important;
}
}
.mat-drawer[style*="visibility: hidden"] {
display: none;
}

View File

@@ -0,0 +1,64 @@
@use "../variables" as *;
html .topbar {
position: sticky;
top: 0;
z-index: 9;
height: $header-height;
.notification-badge{
.mat-badge-content{
left: 80%;
bottom: 85%;
width: 16px;
height: 16px;
}
}
}
.topbar-dd {
min-width: 360px !important;
}
.apps-dd {
min-width: 830px !important;
overflow: unset !important;
.mat-mdc-menu-content {
padding: 0;
}
}
.text-hover-primary:hover {
.hover-text {
color: $primary;
}
}
.upgrade-bg {
position: absolute;
top: 0px;
right: 0px;
height: 100%;
}
.object-cover {
object-fit: cover;
}
.profile-dd {
margin-top: -5px;
margin-left: -5px;
}
.dark-theme {
.topbar {
.mat-mdc-icon-button {
color: $dark-text-secondary !important;
}
.mdc-button {
--mdc-text-button-label-text-color: $dark-text-secondary !important;
}
}
}

View File

@@ -0,0 +1,126 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"Modernize": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular/build:application",
"options": {
"allowedCommonJsDependencies": ["apexcharts", "bezier-easing", "chance"],
"outputPath": {
"base": "dist/Modernize"
},
"index": "src/index.html",
"polyfills": ["zone.js"],
"tsConfig": "tsconfig.app.json",
"inlineStyleLanguage": "scss",
"assets": ["src/favicon.ico", "src/assets"],
"styles": [
"src/styles.scss",
"src/assets/scss/style.scss",
"node_modules/ngx-toastr/toastr.css",
"node_modules/angular-calendar/css/angular-calendar.css",
"node_modules/highlight.js/styles/atom-one-dark.min.css"
],
"scripts": [],
"browser": "src/main.ts"
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "12mb",
"maximumError": "12mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "12mb",
"maximumError": "12mb"
}
],
"outputHashing": "all"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular/build:dev-server",
"configurations": {
"production": {
"buildTarget": "Modernize:build:production"
},
"development": {
"buildTarget": "Modernize:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular/build:extract-i18n",
"options": {
"buildTarget": "Modernize:build"
}
},
"test": {
"builder": "@angular/build:karma",
"options": {
"polyfills": ["zone.js", "zone.js/testing"],
"tsConfig": "tsconfig.spec.json",
"inlineStyleLanguage": "scss",
"assets": ["src/favicon.ico", "src/assets"],
"styles": ["src/styles.scss"],
"scripts": []
}
}
}
}
},
"cli": {
"analytics": false
},
"schematics": {
"@schematics/angular:component": {
"type": "component"
},
"@schematics/angular:directive": {
"type": "directive"
},
"@schematics/angular:service": {
"type": "service"
},
"@schematics/angular:guard": {
"typeSeparator": "."
},
"@schematics/angular:interceptor": {
"typeSeparator": "."
},
"@schematics/angular:module": {
"typeSeparator": "."
},
"@schematics/angular:pipe": {
"typeSeparator": "."
},
"@schematics/angular:resolver": {
"typeSeparator": "."
}
}
}

View File

@@ -0,0 +1,62 @@
{
"name": "modernize",
"version": "3.1.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test"
},
"private": true,
"dependencies": {
"@angular/animations": "^20.0.4",
"@angular/cdk": "^20.0.3",
"@angular/common": "^20.0.4",
"@angular/compiler": "^20.0.4",
"@angular/core": "^20.0.4",
"@angular/forms": "^20.0.4",
"@angular/material": "^20.0.3",
"@angular/platform-browser": "^20.0.4",
"@angular/platform-browser-dynamic": "^20.0.4",
"@angular/router": "^20.0.4",
"@ng-matero/extensions": "^20.1.0",
"@ngx-translate/core": "^16.0.4",
"@ngx-translate/http-loader": "^16.0.1",
"angular-calendar": "^0.31.1",
"angular-tabler-icons": "^3.26.0",
"apexcharts": "^4.7.0",
"chance": "^1.1.13",
"date-fns": "^4.1.0",
"highlight.js": "^11.11.1",
"ng-apexcharts": "^1.16.0",
"ng2-search-filter": "^0.5.1",
"ngx-dropzone": "^3.1.0",
"ngx-editor": "^19.0.0-beta.1",
"ngx-highlightjs": "^14.0.1",
"ngx-owl-carousel-o": "^20.0.0",
"ngx-pagination": "^6.0.3",
"ngx-permissions": "^19.0.0",
"ngx-scrollbar": "^18.0.0",
"ngx-toastr": "^19.0.0",
"rxjs": "~7.8.2",
"sass": "^1.89.2",
"tslib": "^2.8.1",
"zone.js": "~0.15.1"
},
"devDependencies": {
"@angular/build": "^20.0.3",
"@angular/cli": "~20.0.3",
"@angular/compiler-cli": "^20.0.4",
"@types/chance": "^1.1.6",
"@types/date-fns": "^2.6.3",
"@types/jasmine": "~5.1.8",
"jasmine-core": "~5.8.0",
"karma": "~6.4.4",
"karma-chrome-launcher": "~3.2.0",
"karma-coverage": "~2.2.1",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.1.0",
"typescript": "~5.8.3"
}
}

View File

@@ -0,0 +1,107 @@
import { Routes } from '@angular/router';
import { BlankComponent } from './layouts/blank/blank.component';
import { FullComponent } from './layouts/full/full.component';
export const routes: Routes = [
{
path: '',
component: FullComponent,
children: [
{
path: '',
redirectTo: '/dashboards/dashboard1',
pathMatch: 'full',
},
{
path: 'starter',
loadChildren: () =>
import('./pages/pages.routes').then((m) => m.PagesRoutes),
},
{
path: 'dashboards',
loadChildren: () =>
import('./pages/dashboards/dashboards.routes').then(
(m) => m.DashboardsRoutes
),
},
{
path: 'forms',
loadChildren: () =>
import('./pages/forms/forms.routes').then((m) => m.FormsRoutes),
},
{
path: 'charts',
loadChildren: () =>
import('./pages/charts/charts.routes').then((m) => m.ChartsRoutes),
},
{
path: 'apps',
loadChildren: () =>
import('./pages/apps/apps.routes').then((m) => m.AppsRoutes),
},
{
path: 'widgets',
loadChildren: () =>
import('./pages/widgets/widgets.routes').then((m) => m.WidgetsRoutes),
},
{
path: 'tables',
loadChildren: () =>
import('./pages/tables/tables.routes').then((m) => m.TablesRoutes),
},
{
path: 'datatable',
loadChildren: () =>
import('./pages/datatable/datatable.routes').then(
(m) => m.DatatablesRoutes
),
},
{
path: 'theme-pages',
loadChildren: () =>
import('./pages/theme-pages/theme-pages.routes').then(
(m) => m.ThemePagesRoutes
),
},
{
path: 'ui-components',
loadChildren: () =>
import('./pages/ui-components/ui-components.routes').then(
(m) => m.UiComponentsRoutes
),
},
],
},
{
path: '',
component: BlankComponent,
children: [
{
path: 'authentication',
loadChildren: () =>
import('./pages/authentication/authentication.routes').then(
(m) => m.AuthenticationRoutes
),
},
{
path: 'landingpage',
loadChildren: () =>
import('./pages/theme-pages/landingpage/landingpage.routes').then(
(m) => m.LandingPageRoutes
),
},
{
path: 'front-pages',
loadChildren: () =>
import('./pages/front-pages/front-pages.routes').then(
(m) => m.FrontPagesRoutes
),
},
],
},
{
path: '**',
redirectTo: 'authentication/error',
},
];

View File

@@ -0,0 +1,55 @@
<mat-card class="cardWithShadow">
<mat-card-header>
<mat-card-title>Yearly Breakup</mat-card-title>
</mat-card-header>
<mat-card-content>
<div class="row">
<div class="col-7">
<h4 class="f-s-24">$36,358</h4>
<div class="d-flex align-items-center m-t-16">
<button
mat-mini-fab
class="bg-light-success text-success shadow-none icon-27 d-flex align-items-center justify-content-center"
>
<i-tabler name="arrow-up-right" class="icon-20 d-flex"></i-tabler>
</button>
<div class="f-s-14 f-w-600 m-l-12">+9%</div>
<div class="f-s-14 f-w-400 m-l-4">last year</div>
</div>
<div class="d-flex align-items-center m-t-32">
<div class="d-flex align-items-center">
<i-tabler
name="circle-filled"
class="text-primary icon-12 d-flex"
></i-tabler>
<div class="f-s-14 f-w-400 m-l-12">2025</div>
</div>
<div class="d-flex align-items-center m-l-16">
<i-tabler
name="circle-filled"
class="text-light-primary icon-12 d-flex"
></i-tabler>
<div class="f-s-14 f-w-400 m-l-12">2024</div>
</div>
</div>
</div>
<div class="col-5">
<!-- ---------------------------- -->
<!-- charts here -->
<!-- ---------------------------- -->
<apx-chart
[series]="yearlyChart.series"
[dataLabels]="yearlyChart.dataLabels"
[chart]="yearlyChart.chart"
[legend]="yearlyChart.legend"
[colors]="yearlyChart.colors"
[stroke]="yearlyChart.stroke"
[tooltip]="yearlyChart.tooltip"
[plotOptions]="yearlyChart.plotOptions"
[responsive]="yearlyChart.responsive"
></apx-chart>
</div>
</div>
</mat-card-content>
</mat-card>

View File

@@ -0,0 +1,25 @@
export interface AppSettings {
dir: 'ltr' | 'rtl';
theme: string;
sidenavOpened: boolean;
sidenavCollapsed: boolean;
boxed: boolean;
horizontal: boolean;
activeTheme: string;
language: string;
cardBorder: boolean;
navPos: 'side' | 'top';
}
export const defaults: AppSettings = {
dir: 'ltr',
theme: 'dark',
sidenavOpened: false,
sidenavCollapsed: false,
boxed: true,
horizontal: false,
cardBorder: false,
activeTheme: 'blue_theme',
language: 'en-us',
navPos: 'side',
};

View File

@@ -0,0 +1,197 @@
<span [dir]="options.dir!">
<mat-sidenav-container class="mainWrapper" autosize autoFocus [ngClass]="{
'sidebarNav-mini':
options.sidenavCollapsed && options.navPos !== 'top' && !resView,
'sidebarNav-horizontal': options.horizontal,
cardBorder: options.cardBorder
}">
<!-- ============================================================== -->
<!-- Vertical Sidebar -->
<!-- ============================================================== -->
@if (!options.horizontal) {
<mat-sidenav #leftsidenav [mode]="isOver ? 'over' : 'side'" [opened]="
options.navPos === 'side' &&
options.sidenavOpened &&
!isOver &&
!resView
" (openedChange)="onSidenavOpenedChange($event)" (closedStart)="onSidenavClosedStart()" class="sidebarNav">
<div class="flex-layout">
<app-sidebar (toggleMobileNav)="sidenav.toggle()" [showToggle]="isOver"></app-sidebar>
<ng-scrollbar class="position-relative" style="height: 100%">
<mat-nav-list class="sidebar-list">
@for(item of navItems; track item) {
<app-nav-item [item]="item" (notify)="sidenav.toggle()" class="top-parent">
</app-nav-item>
}
</mat-nav-list>
</ng-scrollbar>
<div class="p-24 m-t-auto profile-bar">
<div class="bg-light-secondary d-flex align-items-center rounded p-16">
<img src="/assets/images/profile/user-1.jpg" class="rounded-circle" width="40" />
<div class="m-l-16">
<h4 class="f-w-600">Mathew</h4>
<span class="f-s-12">Designer</span>
</div>
<div class="m-l-auto">
<a mat-icon-button [routerLink]="['/authentication/login']" class="d-flex justify-content-center">
<i-tabler name="power" class="text-primary icon-18 d-flex"></i-tabler>
</a>
</div>
</div>
</div>
</div>
</mat-sidenav>
}
<!-- ============================================================== -->
<!-- horizontal Sidebar -->
<!-- ============================================================== -->
@if (resView) {
<mat-sidenav #leftsidenav [mode]="'over'" [opened]="options.sidenavOpened && !isTablet"
(openedChange)="onSidenavOpenedChange($event)" (closedStart)="onSidenavClosedStart()" class="sidebarNav">
<app-sidebar> </app-sidebar>
<ng-scrollbar class="position-relative" style="height: 100%">
<mat-nav-list class="sidebar-list">
@for(item of navItems; track item) {
<app-nav-item [item]="item" (notify)="sidenav.toggle()">
</app-nav-item>
}
</mat-nav-list>
</ng-scrollbar>
<div class="p-24 m-t-auto profile-bar">
<div class="bg-light-secondary d-flex align-items-center rounded p-16">
<img src="/assets/images/profile/user-1.jpg" class="rounded-circle" width="40" />
<div class="m-l-16">
<h4 class="f-w-600">Mathew</h4>
<span class="f-s-12">Designer</span>
</div>
<div class="m-l-auto">
<a mat-icon-button [routerLink]="['/authentication/login']" class="d-flex justify-content-center">
<i-tabler name="power" class="text-primary icon-18 d-flex"></i-tabler>
</a>
</div>
</div>
</div>
</mat-sidenav>
}
<!-- ============================================================== -->
<!-- Main Content -->
<!-- ============================================================== -->
<mat-sidenav-content class="contentWrapper" #content>
<!-- ============================================================== -->
<!-- VerticalHeader -->
<!-- ============================================================== -->
@if (!options.horizontal) {
<app-header [showToggle]="!isOver" (toggleCollapsed)="toggleCollapsed()" (toggleMobileNav)="sidenav.toggle()"
(toggleMobileFilterNav)="toggleFilterNav()" (optionsChange)="receiveOptions($event)"></app-header>
} @else {
<!-- horizontal header -->
<app-horizontal-header (toggleMobileNav)="sidenav.toggle()" (toggleMobileFilterNav)="toggleFilterNav()"
(optionsChange)="receiveOptions($event)"></app-horizontal-header>
} @if(options.horizontal) {
<app-horizontal-sidebar></app-horizontal-sidebar>
}
<main class="pageWrapper" [ngClass]="{
maxWidth: options.boxed
}">
<app-breadcrumb></app-breadcrumb>
<!-- ============================================================== -->
<!-- Outlet -->
<!-- ============================================================== -->
<router-outlet></router-outlet>
<div class="customizerBtn">
<button mat-fab class="bg-primary text-white" (click)="customizerRight.toggle()">
<mat-icon>settings</mat-icon>
</button>
</div>
</main>
<!-- ------------------------------------------------------------------
Mobile Apps Sidebar
------------------------------------------------------------------ -->
<div [class.open]="isFilterNavOpen" class="filter-sidebar">
<div>
<div class="d-flex justify-content-between align-items-center">
<div class="branding">
@if(options.theme === 'light') {
<a href="/">
<img src="./assets/images/logos/dark-logo.svg" class="align-middle m-2" alt="logo" />
</a>
} @else {
<a href="/">
<img src="./assets/images/logos/light-logo.svg" class="align-middle m-2" alt="logo" />
</a>
}
</div>
<button mat-icon-button (click)="isFilterNavOpen = !isFilterNavOpen" class="d-flex justify-content-center">
<i-tabler name="x" class="icon-18 d-flex"></i-tabler>
</button>
</div>
<mat-accordion>
<mat-expansion-panel class="shadow-none">
<mat-expansion-panel-header>
<mat-panel-title class="f-s-16 f-w-500"> Apps </mat-panel-title>
</mat-expansion-panel-header>
<div>
<div class="row">
@for(appdd of apps; track appdd.img) {
<div class="col-12 text-hover-primary">
<a [routerLink]="[appdd.link]" class="d-flex align-items-center text-decoration-none m-b-24 gap-16">
<button mat-mini-fab class="text-primary bg-light-primary shadow-none rounded">
<img [src]="appdd.img" width="20" />
</button>
<div>
<h5 class="f-s-14 f-w-600 m-0 textprimary f-s-14 hover-text">
{{ appdd.title }}
</h5>
<span class="f-s-14 f-s-12">{{ appdd.subtitle }}</span>
</div>
</a>
</div>
}
</div>
<h4 class="f-s-18 f-w-600 m-b-16">Quick Links</h4>
@for(quicklink of quicklinks; track quicklink.title) {
<div class="text-hover-primary">
<a [routerLink]="['quicklink.link']"
class="hover-text text-decoration-none f-s-14 f-w-600 d-block p-y-8">{{ quicklink.title }}</a>
</div>
}
</div>
</mat-expansion-panel>
</mat-accordion>
<div class="p-x-16">
<a [routerLink]="['/apps/calendar']"
class="d-flex align-items-center text-decoration-none f-s-14 p-y-16 gap-8">
<span class="f-s-15 f-w-500 m-l-8">Calendar</span>
</a>
<a [routerLink]="['/apps/chat']" class="d-flex align-items-center text-decoration-none f-s-14 p-y-16">
<span class="f-s-15 f-w-500 m-l-8">Chat</span>
</a>
<a [routerLink]="['/apps/email/inbox']"
class="d-flex align-items-center text-decoration-none f-s-14 p-y-16 gap-8">
<span class="f-s-15 f-w-500 m-l-8">Email</span>
</a>
</div>
</div>
</div>
</mat-sidenav-content>
<mat-sidenav #customizerRight mode="over" position="end">
<div class="p-x-16 p-y-20 d-flex align-items-center justify-content-between">
<h3 class="f-s-21 f-w-600">Settings</h3>
<button class="d-lg-none" mat-button (click)="customizerRight.toggle()">
Close
</button>
</div>
<mat-divider></mat-divider>
<app-customizer (optionsChange)="receiveOptions($event)"></app-customizer>
</mat-sidenav>
</mat-sidenav-container>
</span>

View File

@@ -0,0 +1,284 @@
import { BreakpointObserver, MediaMatcher } from '@angular/cdk/layout';
import { ChangeDetectorRef, Component, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
import { Subscription } from 'rxjs';
import { MatSidenav, MatSidenavContent } from '@angular/material/sidenav';
import { CoreService } from 'src/app/services/core.service';
import { AppSettings } from 'src/app/config';
import { filter } from 'rxjs/operators';
import { NavigationEnd, Router } from '@angular/router';
import { navItems } from './vertical/sidebar/sidebar-data';
import { NavService } from '../../services/nav.service';
import { AppNavItemComponent } from './vertical/sidebar/nav-item/nav-item.component';
import { RouterModule } from '@angular/router';
import { MaterialModule } from 'src/app/material.module';
import { CommonModule } from '@angular/common';
import { SidebarComponent } from './vertical/sidebar/sidebar.component';
import { NgScrollbarModule } from 'ngx-scrollbar';
import { TablerIconsModule } from 'angular-tabler-icons';
import { HeaderComponent } from './vertical/header/header.component';
import { AppHorizontalHeaderComponent } from './horizontal/header/header.component';
import { AppHorizontalSidebarComponent } from './horizontal/sidebar/sidebar.component';
import { AppBreadcrumbComponent } from './shared/breadcrumb/breadcrumb.component';
import { CustomizerComponent } from './shared/customizer/customizer.component';
const MOBILE_VIEW = 'screen and (max-width: 768px)';
const TABLET_VIEW = 'screen and (min-width: 769px) and (max-width: 1024px)';
const MONITOR_VIEW = 'screen and (min-width: 1024px)';
const BELOWMONITOR = 'screen and (max-width: 1023px)';
// for mobile app sidebar
interface apps {
id: number;
img: string;
title: string;
subtitle: string;
link: string;
}
interface quicklinks {
id: number;
title: string;
link: string;
}
@Component({
selector: 'app-full',
imports: [
RouterModule,
AppNavItemComponent,
MaterialModule,
CommonModule,
SidebarComponent,
NgScrollbarModule,
TablerIconsModule,
HeaderComponent,
AppHorizontalHeaderComponent,
AppHorizontalSidebarComponent,
AppBreadcrumbComponent,
CustomizerComponent,
],
templateUrl: './full.component.html',
encapsulation: ViewEncapsulation.None
})
export class FullComponent implements OnInit {
navItems = navItems;
@ViewChild('leftsidenav')
public sidenav: MatSidenav;
resView = false;
@ViewChild('content', { static: true }) content!: MatSidenavContent;
//get options from service
options = this.settings.getOptions();
private layoutChangesSubscription = Subscription.EMPTY;
private isMobileScreen = false;
private isContentWidthFixed = true;
private isCollapsedWidthFixed = false;
private htmlElement!: HTMLHtmlElement;
get isOver(): boolean {
return this.isMobileScreen;
}
get isTablet(): boolean {
return this.resView;
}
// for mobile app sidebar
apps: apps[] = [
{
id: 1,
img: '/assets/images/svgs/icon-dd-chat.svg',
title: 'Chat Application',
subtitle: 'Messages & Emails',
link: '/apps/chat',
},
{
id: 2,
img: '/assets/images/svgs/icon-dd-cart.svg',
title: 'Todo App',
subtitle: 'Completed task',
link: '/apps/todo',
},
{
id: 3,
img: '/assets/images/svgs/icon-dd-invoice.svg',
title: 'Invoice App',
subtitle: 'Get latest invoice',
link: '/apps/invoice',
},
{
id: 4,
img: '/assets/images/svgs/icon-dd-date.svg',
title: 'Calendar App',
subtitle: 'Get Dates',
link: '/apps/calendar',
},
{
id: 5,
img: '/assets/images/svgs/icon-dd-mobile.svg',
title: 'Contact Application',
subtitle: '2 Unsaved Contacts',
link: '/apps/contacts',
},
{
id: 6,
img: '/assets/images/svgs/icon-dd-lifebuoy.svg',
title: 'Tickets App',
subtitle: 'Create new ticket',
link: '/apps/tickets',
},
{
id: 7,
img: '/assets/images/svgs/icon-dd-message-box.svg',
title: 'Email App',
subtitle: 'Get new emails',
link: '/apps/email/inbox',
},
{
id: 8,
img: '/assets/images/svgs/icon-dd-application.svg',
title: 'Courses',
subtitle: 'Create new course',
link: '/apps/courses',
},
];
quicklinks: quicklinks[] = [
{
id: 1,
title: 'Pricing Page',
link: '/theme-pages/pricing',
},
{
id: 2,
title: 'Authentication Design',
link: '/authentication/login',
},
{
id: 3,
title: 'Register Now',
link: '/authentication/side-register',
},
{
id: 4,
title: '404 Error Page',
link: '/authentication/error',
},
{
id: 5,
title: 'Notes App',
link: '/apps/notes',
},
{
id: 6,
title: 'Employee App',
link: '/apps/employee',
},
{
id: 7,
title: 'Todo Application',
link: '/apps/todo',
},
{
id: 8,
title: 'Treeview',
link: '/theme-pages/treeview',
},
];
constructor(
private settings: CoreService,
private mediaMatcher: MediaMatcher,
private router: Router,
private breakpointObserver: BreakpointObserver,
private navService: NavService, private cdr: ChangeDetectorRef
) {
this.htmlElement = document.querySelector('html')!;
this.layoutChangesSubscription = this.breakpointObserver
.observe([MOBILE_VIEW, TABLET_VIEW, MONITOR_VIEW, BELOWMONITOR])
.subscribe((state) => {
// SidenavOpened must be reset true when layout changes
this.options.sidenavOpened = true;
this.isMobileScreen = state.breakpoints[BELOWMONITOR];
if (this.options.sidenavCollapsed == false) {
this.options.sidenavCollapsed = state.breakpoints[TABLET_VIEW];
}
this.isContentWidthFixed = state.breakpoints[MONITOR_VIEW];
this.resView = state.breakpoints[BELOWMONITOR];
});
// Initialize project theme with options
this.receiveOptions(this.options);
// This is for scroll to top
this.router.events
.pipe(filter((event) => event instanceof NavigationEnd))
.subscribe((e) => {
this.content.scrollTo({ top: 0 });
});
}
isFilterNavOpen = false;
toggleFilterNav() {
this.isFilterNavOpen = !this.isFilterNavOpen;
console.log('Sidebar open:', this.isFilterNavOpen);
this.cdr.detectChanges(); // Ensures Angular updates the view
}
ngOnInit(): void {}
ngOnDestroy() {
this.layoutChangesSubscription.unsubscribe();
}
toggleCollapsed() {
this.isContentWidthFixed = false;
this.options.sidenavCollapsed = !this.options.sidenavCollapsed;
this.resetCollapsedState();
}
resetCollapsedState(timer = 400) {
setTimeout(() => this.settings.setOptions(this.options), timer);
}
onSidenavClosedStart() {
this.isContentWidthFixed = false;
}
onSidenavOpenedChange(isOpened: boolean) {
this.isCollapsedWidthFixed = !this.isOver;
this.options.sidenavOpened = isOpened;
this.settings.setOptions(this.options);
}
receiveOptions(options: AppSettings): void {
this.toggleDarkTheme(options);
this.toggleColorsTheme(options);
}
toggleDarkTheme(options: AppSettings) {
if (options.theme === 'dark') {
this.htmlElement.classList.add('dark-theme');
this.htmlElement.classList.remove('light-theme');
} else {
this.htmlElement.classList.remove('dark-theme');
this.htmlElement.classList.add('light-theme');
}
}
toggleColorsTheme(options: AppSettings) {
// Remove any existing theme class dynamically
this.htmlElement.classList.forEach((className) => {
if (className.endsWith('_theme')) {
this.htmlElement.classList.remove(className);
}
});
// Add the selected theme class
this.htmlElement.classList.add(options.activeTheme);
}
}

View File

@@ -0,0 +1,296 @@
<mat-toolbar class="topbar horizontal-topbar">
<div class="container">
<div class="d-none d-sm-flex branding">
<app-branding></app-branding>
</div>
<!-- Mobile Menu -->
<button
mat-icon-button
(click)="toggleMobileNav.emit()"
class="d-block d-lg-none"
>
<i-tabler name="menu-2" class="icon-20 d-flex"></i-tabler>
</button>
<!-- --------------------------------------------------------------- -->
<!-- --------------------------------------------------------------- -->
<!-- Search -->
<!-- --------------------------------------------------------------- -->
<button mat-icon-button (click)="openDialog()" class="d-flex">
<i-tabler name="search" class="icon-20 d-flex"></i-tabler>
</button>
<div class="d-none d-lg-flex">
<!-- --------------------------------------------------------------- -->
<!-- Links -->
<!-- --------------------------------------------------------------- -->
<button
mat-button
[matMenuTriggerFor]="appsmenu"
aria-label="Notifications"
>
<div class="d-flex align-items-center">
Apps <i-tabler name="chevron-down" class="icon-16 m-l-4"></i-tabler>
</div>
</button>
<mat-menu #appsmenu="matMenu" class="apps-dd cardWithShadow">
<div class="row">
<div class="col-sm-8 b-r-1 p-r-0">
<div class="p-32 p-b-0">
<div class="row">
@for(appdd of apps; track appdd.title) {
<div class="col-sm-6 text-hover-primary">
<a
[routerLink]="[appdd.link]"
class="d-flex align-items-center text-decoration-none m-b-24"
>
<span
class="text-primary bg-light rounded icon-40 d-flex align-items-center justify-content-center"
>
<img [src]="appdd.img" width="20" />
</span>
<div class="m-l-16">
<h5
class="f-s-14 f-w-600 m-0 textprimary hover-text"
>
{{ appdd.title }}
</h5>
<span class="text-body f-s-12">{{
appdd.subtitle
}}</span>
</div>
</a>
</div>
}
</div>
</div>
<div
class="b-t-1 p-24 d-none d-lg-flex align-items-center justify-content-between"
>
<span
class="d-flex align-items-center f-s-16 f-w-500"
>
<i-tabler name="help" class="icon-20 m-r-8"></i-tabler
>Frequently Asked Questions
</span>
<a
[routerLink]="['/theme-pages/faq']"
mat-flat-button
color="primary"
>Check</a
>
</div>
</div>
<div class="col-sm-4">
<div class="p-x-16 p-y-32">
<h4 class="f-s-18 f-w-600 m-b-16">Quick Links</h4>
@for(quicklink of quicklinks; track quicklink.title) {
<div class="text-hover-primary">
<a
[routerLink]="[quicklink.link]"
class="hover-text text-decoration-none f-s-14 f-w-600 d-block p-y-8"
>{{ quicklink.title }}</a
>
</div>
}
</div>
</div>
</div>
</mat-menu>
<a mat-button [routerLink]="['/apps/chat']">Chat</a>
<a mat-button [routerLink]="['/apps/calendar']">Calendar</a>
<a mat-button [routerLink]="['/apps/email/inbox']">Email</a>
</div>
<span class="flex-1-auto"></span>
<!-- Mobile Menu -->
<button
mat-icon-button
(click)="toggleMobileFilterNav.emit()"
class="d-flex d-lg-none justify-content-center"
>
<i-tabler name="grid-dots" class="icon-20 d-flex"></i-tabler>
</button>
<!-- --------------------------------------------------------------- -->
<!-- langugage Dropdown -->
<!-- --------------------------------------------------------------- -->
<button [matMenuTriggerFor]="flags" mat-icon-button class="m-r-5">
<img
[src]="selectedLanguage.icon"
class="rounded-circle object-cover icon-20"
/>
</button>
<mat-menu #flags="matMenu" class="cardWithShadow">
@for(lang of languages; track lang.icon) {
<button mat-menu-item (click)="changeLanguage(lang)">
<div class="d-flex align-items-center">
<img
[src]="lang.icon"
class="rounded-circle object-cover m-r-8 icon-20"
/>
<span class=" f-s-14">{{ lang.language }}</span>
</div>
</button>
}
</mat-menu>
@if(options.theme=='light'){
<button mat-icon-button aria-label="lightdark" class="d-flex justify-content-center" (click)="setlightDark('dark')" >
<i-tabler class="d-flex icon-22" [name]="'moon'"></i-tabler>
</button>
}@else{
<button mat-icon-button aria-label="lightdark" class="d-flex justify-content-center" (click)="setlightDark('light')">
<i-tabler class="d-flex icon-22" [name]="'sun'"></i-tabler>
</button>
}
<!-- --------------------------------------------------------------- -->
<!-- Notification Dropdown -->
<!-- --------------------------------------------------------------- -->
<button
mat-icon-button matBadge="5"
[matMenuTriggerFor]="notificationmenu"
aria-label="Notifications" class="m-x-5 notification-badge"
>
<i-tabler
class="d-flex"
name="bell"
></i-tabler>
</button>
<mat-menu
#notificationmenu="matMenu"
xPosition="before"
class="topbar-dd cardWithShadow"
>
<div class="d-flex align-items-center p-x-32 p-y-16">
<h6 class="f-s-16 f-w-600 m-0 ">Notifications</h6>
<span class="m-l-auto">
<span class="bg-primary text-white p-x-8 p-y-4 f-w-500 rounded f-s-12"
>5 new</span
>
</span>
</div>
@for(notification of notifications; track notification.title) {
<button mat-menu-item class="p-x-32 p-y-16">
<div class="d-flex align-items-center">
<img [src]="notification.img" class="rounded-circle" width="48" />
<div class="m-l-16">
<h5 class="f-s-14 f-w-600 m-0 ">
{{ notification.title }}
</h5>
<span>{{ notification.subtitle }}</span>
</div>
</div>
</button>
}
<div class="p-y-12 p-x-32">
<button mat-stroked-button color="primary" class="w-100">
See all notifications
</button>
</div>
</mat-menu>
<!-- --------------------------------------------------------------- -->
<!-- profile Dropdown -->
<!-- --------------------------------------------------------------- -->
<button
mat-icon-button
[matMenuTriggerFor]="profilemenu"
aria-label="Notifications"
>
<img
src="/assets/images/profile/user-1.jpg"
class="rounded-circle object-cover icon-35 profile-dd"
width="35"
/>
</button>
<mat-menu
#profilemenu="matMenu"
xPosition="before"
class="topbar-dd cardWithShadow"
>
<div class="p-x-32 p-y-16">
<h6 class="f-s-16 f-w-600 m-0 ">User Profile</h6>
<div class="d-flex align-items-center p-b-24 b-b-1 m-t-16">
<img
src="/assets/images/profile/user-1.jpg"
class="rounded-circle"
width="95"
/>
<div class="m-l-16">
<h6 class="f-s-14 f-w-600 m-0 ">Mathew Anderson</h6>
<span class="f-s-14 d-block m-b-4">Designer</span>
<span class="d-flex align-items-center">
<i-tabler name="mail" class="icon-15 m-r-4"></i-tabler>
info&#64;modernize.com
</span>
</div>
</div>
</div>
<div class="p-x-32">
@for(profile of profiledd; track profile.title) {
<a
class="p-y-16 text-decoration-none d-block text-hover-primary"
[routerLink]="[profile.link]"
>
<div class="d-flex align-items-center">
<button
mat-mini-fab
class="text-primary bg-light-primary shadow-none rounded"
>
<img [src]="profile.img" width="20" />
</button>
<div class="m-l-16">
<h5
class="f-s-14 f-w-600 m-0 textprimary hover-text"
>
{{ profile.title }}
</h5>
<span class="f-s-14 text-body">{{ profile.subtitle }}</span>
</div>
</div>
</a>
}
<!-- upgrade -->
<div
class="p-24 overflow-hidden bg-light-primary rounded position-relative m-y-16"
>
<div class="d-flex align-items-center">
<div>
<h5 class="f-s-18 m-0 f-w-600 m-b-12 ">
Unlimited <br />
Access
</h5>
<button mat-flat-button color="primary">Upgrade</button>
</div>
<div class="m-l-auto">
<img
src="/assets/images/backgrounds/unlimited-bg.png"
alt="upgrade-bg"
class="upgrade-bg"
/>
</div>
</div>
</div>
</div>
<div class="p-y-12 p-x-32">
<a
[routerLink]="['/authentication/login']"
mat-stroked-button
color="primary"
class="w-100"
>Logout</a
>
</div>
</mat-menu>
</div>
</mat-toolbar>

View File

@@ -0,0 +1,633 @@
import { NavItem } from '../../vertical/sidebar/nav-item/nav-item';
export const navItems: NavItem[] = [
{
navCap: 'Home',
},
{
displayName: 'Dashboards',
iconName: 'home',
route: 'dashboards',
children: [
{
displayName: 'Analytical',
iconName: 'point',
route: 'dashboards/dashboard1',
},
{
displayName: 'eCommerce',
iconName: 'point',
route: 'dashboards/dashboard2',
},
],
},
{
displayName: 'Frontend pages',
iconName: 'app-window',
route: 'front-pages',
children: [
{
displayName: 'Home Page',
iconName: 'point',
route: 'front-pages/homepage',
} ,
{
displayName: 'About Us',
iconName: 'point',
route: 'front-pages/about',
} ,
{
displayName: 'Blog',
iconName: 'point',
route: 'front-pages/blog',
} ,
{
displayName: 'Blog Details',
iconName: 'point',
route: 'front-pages/blog-details',
} ,
{
displayName: 'Portfolio',
iconName: 'point',
route: 'front-pages/portfolio',
},
{
displayName: 'Pricing',
iconName: 'point',
route: 'front-pages/pricing',
},
{
displayName: 'Contact',
iconName: 'point',
route: 'front-pages/contact',
}
]
},
{
displayName: 'Apps',
iconName: 'apps',
route: 'apps',
ddType: '',
children: [
{
displayName: 'Chat',
iconName: 'point',
route: 'apps/chat',
},
{
displayName: 'Calendar',
iconName: 'point',
route: 'apps/calendar',
},
{
displayName: 'Email',
iconName: 'point',
route: 'apps/email/inbox',
},
{
displayName: 'Contacts',
iconName: 'point',
route: 'apps/contacts',
},
{
displayName: 'Contact List',
iconName: 'point',
route: 'apps/contact-list',
},
{
displayName: 'Courses',
iconName: 'point',
route: 'apps/courses',
},
{
displayName: 'Employee',
iconName: 'point',
route: 'apps/employee',
},
{
displayName: 'Notes',
iconName: 'point',
route: 'apps/notes',
},
{
displayName: 'Tickets',
iconName: 'point',
route: 'apps/tickets',
},
{
displayName: 'Invoice',
iconName: 'point',
route: 'apps/invoice',
},
{
displayName: 'ToDo',
iconName: 'point',
route: 'apps/todo',
},
{
displayName: 'Kanban',
iconName: 'point',
route: 'apps/kanban',
},
{
displayName: 'Blog',
iconName: 'point',
route: 'apps/blog',
children: [
{
displayName: 'Post',
iconName: 'point',
route: 'apps/blog/post',
},
{
displayName: 'Detail',
iconName: 'point',
route: 'apps/blog/detail/Early Black Friday Amazon deals: cheap TVs, headphones, laptops',
},
],
},
{
displayName: 'User Profile',
iconName: 'point',
route: 'apps/profile-details',
children: [
{
displayName: 'Profile',
iconName: 'point',
route: 'apps/profile-details/profile',
},
{
displayName: 'Followers',
iconName: 'point',
route: 'apps/profile-details/followers',
},
{
displayName: 'Friends',
iconName: 'point',
route: 'apps/profile-details/friends',
},
{
displayName: 'Gellary',
iconName: 'point',
route: 'apps/profile-details/gallery',
},
],
},
{
displayName: 'Ecommerce',
iconName: 'point',
route: 'apps/product',
children: [
{
displayName: 'Product List',
iconName: 'point',
route: 'apps/product/product-list',
},
{
displayName: 'Add Product',
iconName: 'point',
route: 'apps/product/add-product',
},
{
displayName: 'Edit Product',
iconName: 'point',
route: 'apps/product/edit-product',
},
{
displayName: 'Shop',
iconName: 'point',
route: 'apps/product/shop',
},
],
},
],
},
{
displayName: 'Ui',
iconName: 'components',
route: 'ui-components',
ddType: '',
children: [
{
displayName: 'Badge',
iconName: 'point',
route: 'ui-components/badge',
},
{
displayName: 'Expansion Panel',
iconName: 'point',
route: 'ui-components/expansion',
},
{
displayName: 'Chips',
iconName: 'point',
route: 'ui-components/chips',
},
{
displayName: 'Dialog',
iconName: 'point',
route: 'ui-components/dialog',
},
{
displayName: 'Lists',
iconName: 'point',
route: 'ui-components/lists',
},
{
displayName: 'Divider',
iconName: 'point',
route: 'ui-components/divider',
},
{
displayName: 'Menu',
iconName: 'point',
route: 'ui-components/menu',
},
{
displayName: 'Paginator',
iconName: 'point',
route: 'ui-components/paginator',
},
{
displayName: 'Progress Bar',
iconName: 'point',
route: 'ui-components/progress',
},
{
displayName: 'Progress Spinner',
iconName: 'point',
route: 'ui-components/progress-spinner',
},
{
displayName: 'Ripples',
iconName: 'point',
route: 'ui-components/ripples',
},
{
displayName: 'Slide Toggle',
iconName: 'point',
route: 'ui-components/slide-toggle',
},
{
displayName: 'Slider',
iconName: 'point',
route: 'ui-components/slider',
},
{
displayName: 'Snackbar',
iconName: 'point',
route: 'ui-components/snackbar',
},
{
displayName: 'Tabs',
iconName: 'point',
route: 'ui-components/tabs',
},
{
displayName: 'Toolbar',
iconName: 'point',
route: 'ui-components/toolbar',
},
{
displayName: 'Tooltips',
iconName: 'point',
route: 'ui-components/tooltips',
},
],
},
{
displayName: 'Pages',
iconName: 'clipboard',
route: 'theme-pages',
ddType: '',
children: [
{
displayName: 'Treeview',
iconName: 'point',
route: 'theme-pages/treeview',
},
{
displayName: 'Pricing',
iconName: 'point',
route: 'theme-pages/pricing',
},
{
displayName: 'Account Setting',
iconName: 'point',
route: 'theme-pages/account-setting',
},
{
displayName: 'FAQ',
iconName: 'point',
route: 'theme-pages/faq',
},
{
displayName: 'Landingpage',
iconName: 'point',
route: 'landingpage',
},
{
displayName: 'Widgets',
iconName: 'point',
route: 'widgets',
children: [
{
displayName: 'Cards',
iconName: 'point',
route: 'widgets/cards',
},
{
displayName: 'Banners',
iconName: 'point',
route: 'widgets/banners',
},
{
displayName: 'Charts',
iconName: 'point',
route: 'widgets/charts',
},
],
},
{
displayName: 'Charts',
iconName: 'point',
route: 'charts',
children: [
{
displayName: 'Line',
iconName: 'point',
route: '/charts/line',
},
{
displayName: 'Gredient',
iconName: 'point',
route: '/charts/gredient',
},
{
displayName: 'Area',
iconName: 'point',
route: '/charts/area',
},
{
displayName: 'Candlestick',
iconName: 'point',
route: '/charts/candlestick',
},
{
displayName: 'Column',
iconName: 'point',
route: '/charts/column',
},
{
displayName: 'Doughnut & Pie',
iconName: 'point',
route: '/charts/doughnut-pie',
},
{
displayName: 'Radialbar & Radar',
iconName: 'point',
route: '/charts/radial-radar',
},
],
},
{
displayName: 'Auth',
iconName: 'point',
route: '/',
children: [
{
displayName: 'Login',
iconName: 'point',
route: '/authentication',
children: [
{
displayName: 'Login 1',
iconName: 'point',
route: '/authentication/login',
},
{
displayName: 'Boxed Login',
iconName: 'point',
route: '/authentication/boxed-login',
},
],
},
{
displayName: 'Register',
iconName: 'point',
route: '/authentication',
children: [
{
displayName: 'Login 1',
iconName: 'point',
route: '/authentication/side-register',
},
{
displayName: 'Boxed Login',
iconName: 'point',
route: '/authentication/boxed-register',
},
],
},
{
displayName: 'Forgot Password',
iconName: 'point',
route: '/authentication',
children: [
{
displayName: 'Side Forgot Password',
iconName: 'point',
route: '/authentication/side-forgot-pwd',
},
{
displayName: 'Boxed Forgot Password',
iconName: 'point',
route: '/authentication/boxed-forgot-pwd',
},
],
},
{
displayName: 'Two Steps',
iconName: 'point',
route: '/authentication',
children: [
{
displayName: 'Side Two Steps',
iconName: 'point',
route: '/authentication/side-two-steps',
},
{
displayName: 'Boxed Two Steps',
iconName: 'point',
route: '/authentication/boxed-two-steps',
},
],
},
{
displayName: 'Error',
iconName: 'point',
route: '/authentication/error',
},
{
displayName: 'Maintenance',
iconName: 'point',
route: '/authentication/maintenance',
},
],
},
],
},
{
displayName: 'Forms',
iconName: 'file-description',
route: 'forms',
ddType: '',
children: [
{
displayName: 'Form elements',
iconName: 'point',
route: 'forms/forms-elements',
children: [
{
displayName: 'Autocomplete',
iconName: 'point',
route: 'forms/forms-elements/autocomplete',
},
{
displayName: 'Button',
iconName: 'point',
route: 'forms/forms-elements/button',
},
{
displayName: 'Checkbox',
iconName: 'point',
route: 'forms/forms-elements/checkbox',
},
{
displayName: 'Radio',
iconName: 'point',
route: 'forms/forms-elements/radio',
},
{
displayName: 'Datepicker',
iconName: 'point',
route: 'forms/forms-elements/datepicker',
},
],
},
{
displayName: 'Form Layouts',
iconName: 'point',
route: '/forms/form-layouts',
},
{
displayName: 'Form Horizontal',
iconName: 'point',
route: '/forms/form-horizontal',
},
{
displayName: 'Form Vertical',
iconName: 'point',
route: '/forms/form-vertical',
},
{
displayName: 'Form Wizard',
iconName: 'point',
route: '/forms/form-wizard',
},
{
displayName: 'Toastr',
iconName: 'point',
route: '/forms/form-toastr',
},
{
displayName: 'Editor',
iconName: 'point',
route: '/forms/form-editor',
},
],
},
{
displayName: 'Tables',
iconName: 'layout',
route: 'tables',
ddType: '',
children: [
{
displayName: 'Basic Table',
iconName: 'point',
route: 'tables/basic-table',
},
{
displayName: 'Dynamic Table',
iconName: 'point',
route: 'tables/dynamic-table',
},
{
displayName: 'Expand Table',
iconName: 'point',
route: 'tables/expand-table',
},
{
displayName: 'Filterable Table',
iconName: 'point',
route: 'tables/filterable-table',
},
{
displayName: 'Footer Row Table',
iconName: 'point',
route: 'tables/footer-row-table',
},
{
displayName: 'HTTP Table',
iconName: 'point',
route: 'tables/http-table',
},
{
displayName: 'Mix Table',
iconName: 'point',
route: 'tables/mix-table',
},
{
displayName: 'Multi Header Footer',
iconName: 'point',
route: 'tables/multi-header-footer-table',
},
{
displayName: 'Pagination Table',
iconName: 'point',
route: 'tables/pagination-table',
},
{
displayName: 'Row Context Table',
iconName: 'point',
route: 'tables/row-context-table',
},
{
displayName: 'Selection Table',
iconName: 'point',
route: 'tables/selection-table',
},
{
displayName: 'Sortable Table',
iconName: 'point',
route: 'tables/sortable-table',
},
{
displayName: 'Sticky Column',
iconName: 'point',
route: 'tables/sticky-column-table',
},
{
displayName: 'Sticky Header Footer',
iconName: 'point',
route: 'tables/sticky-header-footer-table',
},
{
displayName: 'Data table',
iconName: 'point',
route: '/datatable/kichen-sink',
},
],
},
];

View File

@@ -0,0 +1,48 @@
import {
Component,
OnInit,
Input,
ChangeDetectorRef,
OnChanges,
} from '@angular/core';
import { navItems } from './sidebar-data';
import { Router } from '@angular/router';
import { NavService } from '../../../../services/nav.service';
import { MediaMatcher } from '@angular/cdk/layout';
import { AppHorizontalNavItemComponent } from './nav-item/nav-item.component';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-horizontal-sidebar',
imports: [AppHorizontalNavItemComponent, CommonModule],
templateUrl: './sidebar.component.html',
})
export class AppHorizontalSidebarComponent implements OnInit {
navItems = navItems;
parentActive = '';
mobileQuery: MediaQueryList;
private _mobileQueryListener: () => void;
constructor(
public navService: NavService,
public router: Router,
media: MediaMatcher,
changeDetectorRef: ChangeDetectorRef
) {
this.mobileQuery = media.matchMedia('(min-width: 1100px)');
this._mobileQueryListener = () => changeDetectorRef.detectChanges();
this.mobileQuery.addListener(this._mobileQueryListener);
this.router.events.subscribe(
() => (this.parentActive = this.router.url.split('/')[1])
);
}
ngOnInit(): void {
this.parentActive = this.router.url.split('/')[1];
this.router.events.subscribe(() => {
this.parentActive = this.router.url.split('/')[1];
});
}
}

View File

@@ -0,0 +1,43 @@
import { Component, OnInit } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { RouterModule } from '@angular/router';
import { Router, NavigationEnd, ActivatedRoute, Data } from '@angular/router';
import { filter, map, mergeMap } from 'rxjs/operators';
import { TablerIconsModule } from 'angular-tabler-icons';
@Component({
selector: 'app-breadcrumb',
imports: [RouterModule, TablerIconsModule],
templateUrl: './breadcrumb.component.html',
styleUrls: []
})
export class AppBreadcrumbComponent {
// @Input() layout;
pageInfo: Data | any = Object.create(null);
myurl: any = this.router.url.slice(1).split('/');
constructor(
private router: Router,
private activatedRoute: ActivatedRoute,
private titleService: Title
) {
this.router.events
.pipe(filter((event) => event instanceof NavigationEnd))
.pipe(map(() => this.activatedRoute))
.pipe(
map((route) => {
while (route.firstChild) {
route = route.firstChild;
}
return route;
})
)
.pipe(filter((route) => route.outlet === 'primary'))
.pipe(mergeMap((route) => route.data))
// tslint:disable-next-line - Disables all
.subscribe((event) => {
// tslint:disable-next-line - Disables all
this.titleService.setTitle(event['title'] + ' - Angular 20');
this.pageInfo = event;
});
}
}

View File

@@ -0,0 +1,301 @@
<mat-toolbar class="topbar">
<!-- --------------------------------------------------------------- -->
<!-- Desktop Menu -->
@if(showToggle) {
<button
mat-icon-button
(click)="toggleCollapsed.emit()"
class="d-flex justify-content-center"
>
<i-tabler name="menu-2" class="icon-20 d-flex"></i-tabler>
</button>
}
<!-- Mobile Menu -->
@if(!showToggle) {
<button
mat-icon-button
(click)="toggleMobileNav.emit()"
class="d-flex justify-content-center"
>
<i-tabler name="menu-2" class="icon-20 d-flex"></i-tabler>
</button>
}
<!-- --------------------------------------------------------------- -->
<!-- --------------------------------------------------------------- -->
<!-- Search -->
<!-- --------------------------------------------------------------- -->
<button
mat-icon-button
(click)="openDialog()"
class="d-flex justify-content-center"
>
<i-tabler name="search" class="icon-20 d-flex"></i-tabler>
</button>
<div class="d-none d-lg-flex">
<!-- --------------------------------------------------------------- -->
<!-- Links -->
<!-- --------------------------------------------------------------- -->
<button
mat-button
[matMenuTriggerFor]="appsmenu"
aria-label="Notifications"
>
<div class="d-flex align-items-center">
Apps <i-tabler name="chevron-down" class="icon-16 m-l-4"></i-tabler>
</div>
</button>
<mat-menu #appsmenu="matMenu" class="apps-dd cardWithShadow">
<div class="row">
<div class="col-sm-8 b-r-1 p-r-0">
<div class="p-32 p-b-0">
<div class="row">
@for(appdd of apps; track appdd.title) {
<div class="col-sm-6 text-hover-primary">
<a
[routerLink]="[appdd.link]"
class="d-flex align-items-center text-decoration-none m-b-24"
>
<span
class="text-primary bg-light rounded icon-40 d-flex align-items-center justify-content-center"
>
<img [src]="appdd.img" width="20" />
</span>
<div class="m-l-16">
<h5
class="f-s-14 f-w-600 m-0 textprimary hover-text"
>
{{ appdd.title }}
</h5>
<span class="f-s-12 text-body">{{ appdd.subtitle }}</span>
</div>
</a>
</div>
}
</div>
</div>
<div
class="b-t-1 p-24 d-none d-lg-flex align-items-center justify-content-between"
>
<span
class="d-flex align-items-center f-s-16 f-w-500"
>
<i-tabler name="help" class="icon-20 m-r-8"></i-tabler>Frequently
Asked Questions
</span>
<a
[routerLink]="['/theme-pages/faq']"
mat-flat-button
color="primary"
>Check</a
>
</div>
</div>
<div class="col-sm-4">
<div class="p-x-16 p-y-32">
<h4 class="f-s-18 f-w-600 m-b-16">Quick Links</h4>
@for(quicklink of quicklinks; track quicklink.title) {
<div class="text-hover-primary">
<a
[routerLink]="[quicklink.link]"
class="hover-text text-decoration-none f-s-14 f-w-600 d-block p-y-8"
>{{ quicklink.title }}</a
>
</div>
}
</div>
</div>
</div>
</mat-menu>
<a mat-button [routerLink]="['/apps/chat']">Chat</a>
<a mat-button [routerLink]="['/apps/calendar']">Calendar</a>
<a mat-button [routerLink]="['/apps/email/inbox']">Email</a>
</div>
<span class="flex-1-auto"></span>
<!-- Mobile Menu -->
<button
mat-icon-button
(click)="toggleMobileFilterNav.emit()"
class="d-flex d-lg-none justify-content-center"
>
<i-tabler name="grid-dots" class="icon-20 d-flex"></i-tabler>
</button>
<!-- --------------------------------------------------------------- -->
<!-- langugage Dropdown -->
<!-- --------------------------------------------------------------- -->
<button [matMenuTriggerFor]="flags" mat-icon-button class="m-r-5">
<img
[src]="selectedLanguage.icon"
class="rounded-circle object-cover icon-20"
/>
</button>
<mat-menu #flags="matMenu" class="cardWithShadow">
@for(lang of languages; track lang.icon) {
<button mat-menu-item (click)="changeLanguage(lang)">
<div class="d-flex align-items-center">
<img
[src]="lang.icon"
class="rounded-circle object-cover m-r-8 icon-20"
/>
<span class=" f-s-14">{{ lang.language }}</span>
</div>
</button>
}
</mat-menu>
@if(options.theme=='light'){
<button mat-icon-button aria-label="lightdark" class="d-flex justify-content-center" (click)="setlightDark('dark')" >
<i-tabler class="d-flex icon-22" [name]="'moon'"></i-tabler>
</button>
}@else{
<button mat-icon-button aria-label="lightdark" class="d-flex justify-content-center" (click)="setlightDark('light')">
<i-tabler class="d-flex icon-22" [name]="'sun'"></i-tabler>
</button>
}
<!-- --------------------------------------------------------------- -->
<!-- Notification Dropdown -->
<!-- --------------------------------------------------------------- -->
<button
mat-icon-button matBadge="5"
[matMenuTriggerFor]="notificationmenu"
aria-label="Notifications" class="m-x-5 notification-badge"
>
<i-tabler
class="d-flex"
name="bell"
></i-tabler>
</button>
<mat-menu #notificationmenu="matMenu" class="topbar-dd cardWithShadow">
<div class="d-flex align-items-center p-x-32 p-y-16">
<h6 class="f-s-16 f-w-600 m-0 ">Notifications</h6>
<span class="m-l-auto">
<span class="bg-primary text-white p-x-8 p-y-4 f-w-500 rounded f-s-12"
>5 new</span
>
</span>
</div>
@for(notification of notifications; track notification.title) {
<button mat-menu-item class="p-x-32 p-y-16">
<div class="d-flex align-items-center">
<img [src]="notification.img" class="rounded-circle" width="48" />
<div class="m-l-16">
<h5 class="f-s-14 f-w-600 m-0 ">
{{ notification.title }}
</h5>
<span>{{ notification.subtitle }}</span>
</div>
</div>
</button>
}
<div class="p-y-12 p-x-32">
<button mat-stroked-button color="primary" class="w-100">
See all notifications
</button>
</div>
</mat-menu>
<!-- --------------------------------------------------------------- -->
<!-- profile Dropdown -->
<!-- --------------------------------------------------------------- -->
<button
mat-icon-button
[matMenuTriggerFor]="profilemenu"
aria-label="Notifications" class="m-l-8"
>
<img
src="/assets/images/profile/user-1.jpg"
class="rounded-circle object-cover icon-35 profile-dd"
width="35"
/>
</button>
<mat-menu #profilemenu="matMenu" class="topbar-dd cardWithShadow">
<ng-scrollbar class="position-relative" style="height: 647px">
<div class="p-x-32 p-y-16">
<h6 class="f-s-16 f-w-600 m-0 ">User Profile</h6>
<div class="d-flex align-items-center p-b-24 b-b-1 m-t-16">
<img
src="/assets/images/profile/user-1.jpg"
class="rounded-circle"
width="95"
/>
<div class="m-l-16">
<h6 class="f-s-14 f-w-600 m-0 ">Mathew Anderson</h6>
<span class="f-s-14 d-block m-b-4">Designer</span>
<span class="d-flex align-items-center">
<i-tabler name="mail" class="icon-15 m-r-4"></i-tabler>
info&#64;modernize.com
</span>
</div>
</div>
</div>
<div class="p-x-32">
@for(profile of profiledd; track profile.title) {
<a
class="p-y-16 text-decoration-none d-block text-hover-primary"
[routerLink]="[profile.link]"
>
<div class="d-flex align-items-center">
<button
mat-mini-fab
class="text-primary bg-light shadow-none rounded"
>
<img [src]="profile.img" width="20" />
</button>
<div class="m-l-16">
<h5
class="f-s-14 f-w-600 m-0 textprimary hover-text"
>
{{ profile.title }}
</h5>
<span class="f-s-14 text-body">{{ profile.subtitle }}</span>
</div>
</div>
</a>
}
<!-- upgrade -->
<div
class="p-24 overflow-hidden bg-light-primary rounded position-relative m-y-16"
>
<div class="d-flex align-items-center">
<div>
<h5 class="f-s-18 m-0 f-w-600 m-b-12 ">
Unlimited <br />
Access
</h5>
<button mat-flat-button color="primary">Upgrade</button>
</div>
<div class="m-l-auto">
<img
src="/assets/images/backgrounds/unlimited-bg.png"
alt="upgrade-bg"
class="upgrade-bg"
/>
</div>
</div>
</div>
</div>
<div class="p-y-12 p-x-32">
<a
[routerLink]="['/authentication/login']"
mat-stroked-button
color="primary"
class="w-100"
>Logout</a
>
</div>
</ng-scrollbar>
</mat-menu>
</mat-toolbar>

View File

@@ -0,0 +1,103 @@
import {
Component,
HostBinding,
Input,
OnInit,
OnChanges,
Output,
EventEmitter,
} from '@angular/core';
import { NavItem } from './nav-item';
import { Router } from '@angular/router';
import { NavService } from '../../../../../services/nav.service';
import {
animate,
state,
style,
transition,
trigger,
} from '@angular/animations';
import { TranslateModule } from '@ngx-translate/core';
import { TablerIconsModule } from 'angular-tabler-icons';
import { MaterialModule } from 'src/app/material.module';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-nav-item',
imports: [TranslateModule, TablerIconsModule, MaterialModule, CommonModule],
templateUrl: './nav-item.component.html',
styleUrls: [],
animations: [
trigger('indicatorRotate', [
state('collapsed', style({ transform: 'rotate(0deg)' })),
state('expanded', style({ transform: 'rotate(180deg)' })),
transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4,0.0,0.2,1)')),
]),
]
})
export class AppNavItemComponent implements OnChanges {
@Output() toggleMobileLink: any = new EventEmitter<void>();
@Output() notify: EventEmitter<boolean> = new EventEmitter<boolean>();
expanded: any = false;
disabled: any = false;
twoLines: any = false;
@HostBinding('attr.aria-expanded') ariaExpanded = this.expanded;
@Input() item: NavItem | any;
@Input() depth: any;
constructor(public navService: NavService, public router: Router) {
if (this.depth === undefined) {
this.depth = 0;
}
}
ngOnChanges() {
const url = this.navService.currentUrl();
if (this.item.route && url) {
this.expanded = url.indexOf(`/${this.item.route}`) === 0;
this.ariaExpanded = this.expanded;
}
}
onItemSelected(item: NavItem) {
if (!item.children || !item.children.length) {
this.router.navigate([item.route]);
}
if (item.children && item.children.length) {
this.expanded = !this.expanded;
}
//scroll
window.scroll({
top: 0,
left: 0,
behavior: 'smooth',
});
if (!this.expanded) {
if (window.innerWidth < 1024) {
this.notify.emit();
}
}
}
onSubItemSelected(item: NavItem) {
if (!item.children || !item.children.length) {
if (this.expanded && window.innerWidth < 1024) {
this.notify.emit();
}
}
}
isDirectlyActive(item: NavItem): boolean {
return !!item.route && this.router.isActive(item.route, true);
}
isChildActive(item: NavItem): boolean {
if (!item.children) return false;
return item.children.some(
(child) => this.isDirectlyActive(child) || this.isChildActive(child)
);
}
}

View File

@@ -0,0 +1,705 @@
import { NavItem } from './nav-item/nav-item';
export const navItems: NavItem[] = [
{
navCap: 'Home',
},
{
displayName: 'Analytical',
iconName: 'aperture',
route: '/dashboards/dashboard1',
},
{
displayName: 'eCommerce',
iconName: 'shopping-cart',
route: '/dashboards/dashboard2',
},
{
displayName: 'Frontend pages',
iconName: 'app-window',
route: 'front-pages',
children: [
{
displayName: 'Home Page',
iconName: 'point',
route: 'front-pages/homepage',
} ,
{
displayName: 'About Us',
iconName: 'point',
route: 'front-pages/about',
} ,
{
displayName: 'Blog',
iconName: 'point',
route: 'front-pages/blog',
} ,
{
displayName: 'Blog Details',
iconName: 'point',
route: 'front-pages/blog-details',
} ,
{
displayName: 'Portfolio',
iconName: 'point',
route: 'front-pages/portfolio',
},
{
displayName: 'Pricing',
iconName: 'point',
route: 'front-pages/pricing',
},
{
displayName: 'Contact',
iconName: 'point',
route: 'front-pages/contact',
}
]
},
{
navCap: 'Apps',
},
{
displayName: 'Chat',
iconName: 'message-2',
route: 'apps/chat',
},
{
displayName: 'Calendar',
iconName: 'calendar-event',
route: 'apps/calendar',
},
{
displayName: 'Email',
iconName: 'mail',
route: 'apps/email/inbox',
},
{
displayName: 'Kanban',
iconName: 'checklist',
route: 'apps/kanban',
},
{
displayName: 'User Profile',
iconName: 'user-circle',
route: 'apps/profile-details',
chip: true,
chipClass: 'bg-error text-white',
chipContent: 'New',
children: [
{
displayName: 'Profile',
iconName: 'point',
route: 'apps/profile-details/profile',
},
{
displayName: 'Followers',
iconName: 'point',
route: 'apps/profile-details/followers',
},
{
displayName: 'Friends',
iconName: 'point',
route: 'apps/profile-details/friends',
},
{
displayName: 'Gellary',
iconName: 'point',
route: 'apps/profile-details/gallery',
},
],
},
{
displayName: 'Ecommerce',
iconName: 'basket',
route: 'apps/product',
chip: true,
chipClass: 'border-error text-error',
chipContent: 'New',
children: [
{
displayName: 'Product List',
iconName: 'point',
route: 'apps/product/product-list',
},
{
displayName: 'Add Product',
iconName: 'point',
route: 'apps/product/add-product',
},
{
displayName: 'Edit Product',
iconName: 'point',
route: 'apps/product/edit-product',
},
{
displayName: 'Shop',
iconName: 'point',
route: 'apps/product/shop',
},
],
},
{
displayName: 'Contacts',
iconName: 'phone',
route: 'apps/contacts',
},
{
displayName: 'Courses',
iconName: 'certificate',
route: 'apps/courses',
},
{
displayName: 'Employee',
iconName: 'brand-ctemplar',
route: 'apps/employee',
},
{
displayName: 'Notes',
iconName: 'note',
route: 'apps/notes',
},
{
displayName: 'Tickets',
iconName: 'ticket',
route: 'apps/tickets',
},
{
displayName: 'Contact List',
iconName: 'phone',
route: 'apps/contact-list',
},
{
displayName: 'Invoice',
iconName: 'file-invoice',
route: 'apps/invoice',
children: [
{
displayName: 'List',
iconName: 'point',
route: 'apps/invoice/list',
},
{
displayName: 'Detail',
iconName: 'point',
route: 'apps/invoice/viewInvoice/101',
},
{
displayName: 'Create',
iconName: 'point',
route: 'apps/invoice/addInvoice',
},
{
displayName: 'Edit',
iconName: 'point',
route: 'apps/invoice/editinvoice/101',
},
],
},
{
displayName: 'ToDo',
iconName: 'edit',
route: 'apps/todo',
},
{
displayName: 'Blog',
iconName: 'chart-donut-3',
route: 'apps/blog',
children: [
{
displayName: 'Post',
iconName: 'point',
route: 'apps/blog/post',
},
{
displayName: 'Detail',
iconName: 'point',
route: 'apps/blog/detail/Early Black Friday Amazon deals: cheap TVs, headphones, laptops',
},
],
},
{
navCap: 'Pages',
},
{
displayName: 'Roll Base Access',
iconName: 'lock-access',
route: 'apps/permission',
},
{
displayName: 'Treeview',
iconName: 'git-merge',
route: 'theme-pages/treeview',
},
{
displayName: 'Pricing',
iconName: 'currency-dollar',
route: 'theme-pages/pricing',
},
{
displayName: 'Account Setting',
iconName: 'user-circle',
route: 'theme-pages/account-setting',
},
{
displayName: 'FAQ',
iconName: 'help',
route: 'theme-pages/faq',
},
{
displayName: 'Landingpage',
iconName: 'app-window',
route: 'landingpage',
},
{
displayName: 'Widgets',
iconName: 'layout',
route: 'widgets',
children: [
{
displayName: 'Cards',
iconName: 'point',
route: 'widgets/cards',
},
{
displayName: 'Banners',
iconName: 'point',
route: 'widgets/banners',
},
{
displayName: 'Charts',
iconName: 'point',
route: 'widgets/charts',
},
],
},
{
navCap: 'Forms',
},
{
displayName: 'Form elements',
iconName: 'apps',
route: 'forms/forms-elements',
children: [
{
displayName: 'Autocomplete',
iconName: 'point',
route: 'forms/forms-elements/autocomplete',
},
{
displayName: 'Button',
iconName: 'point',
route: 'forms/forms-elements/button',
},
{
displayName: 'Checkbox',
iconName: 'point',
route: 'forms/forms-elements/checkbox',
},
{
displayName: 'Radio',
iconName: 'point',
route: 'forms/forms-elements/radio',
},
{
displayName: 'Datepicker',
iconName: 'point',
route: 'forms/forms-elements/datepicker',
},
],
},
{
displayName: 'Form Layouts',
iconName: 'file-description',
route: '/forms/form-layouts',
},
{
displayName: 'Form Horizontal',
iconName: 'box-align-bottom',
route: '/forms/form-horizontal',
},
{
displayName: 'Form Vertical',
iconName: 'box-align-left',
route: '/forms/form-vertical',
},
{
displayName: 'Form Wizard',
iconName: 'files',
route: '/forms/form-wizard',
},
{
displayName: 'Toastr',
iconName: 'notification',
route: '/forms/form-toastr',
},
{
displayName: 'Editor',
iconName: 'edit',
route: '/forms/form-editor',
chip: true,
chipClass: 'bg-error text-white',
chipContent: 'New',
},
{
navCap: 'Tables',
},
{
displayName: 'Tables',
iconName: 'layout',
route: 'tables',
children: [
{
displayName: 'Basic Table',
iconName: 'point',
route: 'tables/basic-table',
},
{
displayName: 'Dynamic Table',
iconName: 'point',
route: 'tables/dynamic-table',
},
{
displayName: 'Expand Table',
iconName: 'point',
route: 'tables/expand-table',
},
{
displayName: 'Filterable Table',
iconName: 'point',
route: 'tables/filterable-table',
},
{
displayName: 'Footer Row Table',
iconName: 'point',
route: 'tables/footer-row-table',
},
{
displayName: 'HTTP Table',
iconName: 'point',
route: 'tables/http-table',
},
{
displayName: 'Mix Table',
iconName: 'point',
route: 'tables/mix-table',
},
{
displayName: 'Multi Header Footer',
iconName: 'point',
route: 'tables/multi-header-footer-table',
},
{
displayName: 'Pagination Table',
iconName: 'point',
route: 'tables/pagination-table',
},
{
displayName: 'Row Context Table',
iconName: 'point',
route: 'tables/row-context-table',
},
{
displayName: 'Selection Table',
iconName: 'point',
route: 'tables/selection-table',
},
{
displayName: 'Sortable Table',
iconName: 'point',
route: 'tables/sortable-table',
},
{
displayName: 'Sticky Column',
iconName: 'point',
route: 'tables/sticky-column-table',
},
{
displayName: 'Sticky Header Footer',
iconName: 'point',
route: 'tables/sticky-header-footer-table',
},
],
},
{
displayName: 'Data table',
iconName: 'border-outer',
route: '/datatable/kichen-sink',
},
{
navCap: 'Chart',
},
{
displayName: 'Line',
iconName: 'chart-line',
route: '/charts/line',
},
{
displayName: 'Gredient',
iconName: 'chart-arcs',
route: '/charts/gredient',
},
{
displayName: 'Area',
iconName: 'chart-area',
route: '/charts/area',
},
{
displayName: 'Candlestick',
iconName: 'chart-candle',
route: '/charts/candlestick',
},
{
displayName: 'Column',
iconName: 'chart-dots',
route: '/charts/column',
},
{
displayName: 'Doughnut & Pie',
iconName: 'chart-donut-3',
route: '/charts/doughnut-pie',
},
{
displayName: 'Radialbar & Radar',
iconName: 'chart-radar',
route: '/charts/radial-radar',
},
{
navCap: 'UI',
},
{
displayName: 'Ui Components',
iconName: 'box',
route: 'ui-components',
children: [
{
displayName: 'Badge',
iconName: 'point',
route: 'ui-components/badge',
},
{
displayName: 'Expansion Panel',
iconName: 'point',
route: 'ui-components/expansion',
},
{
displayName: 'Chips',
iconName: 'point',
route: 'ui-components/chips',
},
{
displayName: 'Dialog',
iconName: 'point',
route: 'ui-components/dialog',
},
{
displayName: 'Lists',
iconName: 'point',
route: 'ui-components/lists',
},
{
displayName: 'Divider',
iconName: 'point',
route: 'ui-components/divider',
},
{
displayName: 'Menu',
iconName: 'point',
route: 'ui-components/menu',
},
{
displayName: 'Paginator',
iconName: 'point',
route: 'ui-components/paginator',
},
{
displayName: 'Progress Bar',
iconName: 'point',
route: 'ui-components/progress',
},
{
displayName: 'Progress Spinner',
iconName: 'point',
route: 'ui-components/progress-spinner',
},
{
displayName: 'Ripples',
iconName: 'point',
route: 'ui-components/ripples',
},
{
displayName: 'Slide Toggle',
iconName: 'point',
route: 'ui-components/slide-toggle',
},
{
displayName: 'Slider',
iconName: 'point',
route: 'ui-components/slider',
},
{
displayName: 'Snackbar',
iconName: 'point',
route: 'ui-components/snackbar',
},
{
displayName: 'Tabs',
iconName: 'point',
route: 'ui-components/tabs',
},
{
displayName: 'Toolbar',
iconName: 'point',
route: 'ui-components/toolbar',
},
{
displayName: 'Tooltips',
iconName: 'point',
route: 'ui-components/tooltips',
},
],
},
{
navCap: 'Auth',
},
{
displayName: 'Login',
iconName: 'login',
route: '/authentication',
children: [
{
displayName: 'Login 1',
iconName: 'point',
route: '/authentication/login',
},
{
displayName: 'Boxed Login',
iconName: 'point',
route: '/authentication/boxed-login',
},
],
},
{
displayName: 'Register',
iconName: 'user-plus',
route: '/authentication',
children: [
{
displayName: 'Side Register',
iconName: 'point',
route: '/authentication/side-register',
},
{
displayName: 'Boxed Register',
iconName: 'point',
route: '/authentication/boxed-register',
},
],
},
{
displayName: 'Forgot Password',
iconName: 'rotate',
route: '/authentication',
children: [
{
displayName: 'Side Forgot Password',
iconName: 'point',
route: '/authentication/side-forgot-pwd',
},
{
displayName: 'Boxed Forgot Password',
iconName: 'point',
route: '/authentication/boxed-forgot-pwd',
},
],
},
{
displayName: 'Two Steps',
iconName: 'zoom-code',
route: '/authentication',
children: [
{
displayName: 'Side Two Steps',
iconName: 'point',
route: '/authentication/side-two-steps',
},
{
displayName: 'Boxed Two Steps',
iconName: 'point',
route: '/authentication/boxed-two-steps',
},
],
},
{
displayName: 'Error',
iconName: 'alert-circle',
route: '/authentication/error',
},
{
displayName: 'Maintenance',
iconName: 'settings',
route: '/authentication/maintenance',
},
{
navCap: 'Other',
},
{
displayName: 'Menu Level',
iconName: 'box-multiple',
route: '/menu-level',
children: [
{
displayName: 'Menu 1',
iconName: 'point',
route: '/menu-1',
children: [
{
displayName: 'Menu 1',
iconName: 'point',
route: '/menu-1',
},
{
displayName: 'Menu 2',
iconName: 'point',
route: '/menu-2',
},
],
},
{
displayName: 'Menu 2',
iconName: 'point',
route: '/menu-2',
},
],
},
{
displayName: 'Disabled',
iconName: 'ban',
route: '/disabled',
disabled: true,
},
{
displayName: 'Chip',
iconName: 'mood-smile',
route: '/',
chip: true,
chipClass: 'bg-primary text-white',
chipContent: '9',
},
{
displayName: 'Outlined',
iconName: 'mood-smile',
route: '/',
chip: true,
chipClass: 'bg-error text-white',
chipContent: 'outlined',
},
{
displayName: 'External Link',
iconName: 'star',
route: 'https://www.google.com/',
external: true,
},
];

View File

@@ -0,0 +1,89 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
// Material Form Controls
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatRadioModule } from '@angular/material/radio';
import { MatSelectModule } from '@angular/material/select';
import { MatSliderModule } from '@angular/material/slider';
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
// Material Navigation
import { MatMenuModule } from '@angular/material/menu';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatToolbarModule } from '@angular/material/toolbar';
// Material Layout
import { MatCardModule } from '@angular/material/card';
import { MatDividerModule } from '@angular/material/divider';
import { MatExpansionModule } from '@angular/material/expansion';
import { MatGridListModule } from '@angular/material/grid-list';
import { MatListModule } from '@angular/material/list';
import { MatStepperModule } from '@angular/material/stepper';
import { MatTabsModule } from '@angular/material/tabs';
import { MatTreeModule } from '@angular/material/tree';
// Material Buttons & Indicators
import { MatButtonModule } from '@angular/material/button';
import { MatButtonToggleModule } from '@angular/material/button-toggle';
import { MatBadgeModule } from '@angular/material/badge';
import { MatChipsModule } from '@angular/material/chips';
import { MatIconModule } from '@angular/material/icon';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatRippleModule } from '@angular/material/core';
// Material Popups & Modals
import { MatBottomSheetModule } from '@angular/material/bottom-sheet';
import { MatDialogModule } from '@angular/material/dialog';
import { MatSnackBarModule } from '@angular/material/snack-bar';
import { MatTooltipModule } from '@angular/material/tooltip';
// Material Data tables
import { MatPaginatorModule } from '@angular/material/paginator';
import { MatSortModule } from '@angular/material/sort';
import { MatTableModule } from '@angular/material/table';
@NgModule({
declarations: [],
imports: [
],
exports: [
MatAutocompleteModule,
MatCheckboxModule,
MatDatepickerModule,
MatFormFieldModule,
MatInputModule,
MatRadioModule,
MatSelectModule,
MatSliderModule,
MatSlideToggleModule,
MatMenuModule,
MatSidenavModule,
MatToolbarModule,
MatCardModule,
MatDividerModule,
MatExpansionModule,
MatGridListModule,
MatListModule,
MatStepperModule,
MatTabsModule,
MatTreeModule,
MatButtonModule,
MatButtonToggleModule,
MatBadgeModule,
MatChipsModule,
MatIconModule,
MatProgressSpinnerModule,
MatProgressBarModule,
MatRippleModule,
MatBottomSheetModule,
MatDialogModule,
MatSnackBarModule,
MatTooltipModule,
MatPaginatorModule,
MatSortModule,
MatTableModule,
],
})
export class MaterialModule {}

View File

@@ -0,0 +1,123 @@
<mat-card class="chat-app cardWithShadow">
<mat-sidenav-container [ngClass]="{
'side-panel-opened': sidePanelOpened,
'side-panel-closed': !sidePanelOpened
}">
<!-- ---------------------------------------------------- -->
<!-- sidebar -->
<!-- ---------------------------------------------------- -->
<mat-sidenav [mode]="isOver() ? 'over' : 'side'" [opened]="sidePanelOpened" (open)="sidePanelOpened = true"
(close)="sidePanelOpened = false">
<ng-scrollbar class="position-relative" style="height: 100%">
<div class="d-flex align-items-center p-24 gap-16">
<img src="assets/images/profile/user-1.jpg" class="rounded-circle" width="54" />
<div>
<h4 class="f-s-16 f-w-600">Mathew Anderson</h4>
<span class="f-s-12">info&#64;modernize.com</span>
</div>
</div>
<div class="p-x-24">
<!-- search -->
<mat-form-field appearance="outline" class="w-100">
<input matInput placeholder="Search Contacts" [(ngModel)]="searchTerm" (input)="searchMessages()" />
<mat-icon matSuffix>
<i-tabler name="search" class="icon-20 d-flex align-items-end m-t-2"></i-tabler>
</mat-icon>
</mat-form-field>
</div>
@if (filteredMessages() && filteredMessages().length > 0) {
<div class="m-x-24">
<mat-nav-list class="chat-listing">
@for(message of filteredMessages(); track message.from) {
<mat-list-item role="listitem" (click)="selectMessage(message)"
[class.bg-light-primary]="message === selectedMessage()" class="m-b-2 gap-12">
<span matListItemIcon>
<img src="{{ message.photo }}" alt="" width="42" class="rounded-circle" />
</span>
<h3 class="f-w-600 f-s-16" matListItemTitle>
{{ message.from }}
</h3>
<p class="f-s-14 m-t-4" matListItemLine>
{{ message.subject }}
</p>
</mat-list-item>
}
</mat-nav-list>
</div>
} @else {
<div class="p-15 bg-light-primary text-primary rounded m-x-20 m-t-20 text-center">
<span class="f-s-14">No messages found.</span>
</div>
}
</ng-scrollbar>
</mat-sidenav>
<mat-sidenav-content>
<!-- ------------------------------------------- -->
<!-- chat details -->
<!-- ------------------------------------------- -->
<mat-toolbar class="chat-right-panel d-flex align-items-center b-b-1 gap-8">
<button (click)="sidePanelOpened = !sidePanelOpened" mat-icon-button>
<mat-icon>short_text</mat-icon>
</button>
<div class="d-flex align-items-center gap-16">
<img src="{{ selectedMessage()?.photo }}" width="40" class="rounded-circle" />
<div class="f-s-16 f-w-600">
{{ selectedMessage()?.from }}
</div>
</div>
<button [matMenuTriggerFor]="moredd" class="m-l-auto" mat-icon-button>
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #moredd="matMenu" x-position="before">
<button mat-menu-item>Contact info</button>
<button mat-menu-item>Mute</button>
<button mat-menu-item>Delete chat</button>
</mat-menu>
</mat-toolbar>
<!-- ------------------------------------------- -->
<!-- chat content -->
<!-- ------------------------------------------- -->
<ng-scrollbar style="height: calc(100vh - 442px)" class="position-relative">
<mat-card-content class="chat-middle-box p-24">
@for(c of selectedMessage()?.chat; track c) { @if(c.type === 'odd') {
<div class="chat-list odd">
<div class="m-b-15">
<div class="bg-light-primary p-10 rounded d-flex align-items-center gap-16">
<img src="{{ selectedMessage()?.photo }}" class="rounded-circle" width="40" />
<span class="f-s-14">{{ c.msg }}</span>
</div>
<span class="f-s-12">
{{ c.date | date }}
</span>
</div>
</div>
} @else {
<div class="chat-list even">
<div class="m-b-15">
<div class="bg-light-secondary p-10 rounded d-flex align-items-center f-s-14">
{{ c.msg }}
</div>
<span class="f-s-12">
{{ c.date | date }}
</span>
</div>
</div>
} }
</mat-card-content>
</ng-scrollbar>
<mat-divider></mat-divider>
<div class="p-t-20 p-x-24">
<mat-form-field appearance="outline" class="w-100">
<input matInput placeholder="Send message" [ngModel]="msg()" (ngModelChange)="msg.set($event)"
(keydown.enter)="sendMessage()" />
<button mat-icon-button matSuffix (click)="sendMessage()" [disabled]="!msg">
<mat-icon>send</mat-icon>
</button>
</mat-form-field>
</div>
</mat-sidenav-content>
</mat-sidenav-container>
</mat-card>

View File

@@ -0,0 +1,286 @@
import {
Component,
ChangeDetectionStrategy,
Inject,
signal,
DOCUMENT
} from '@angular/core';
import { CommonModule, NgSwitch } from '@angular/common';
import {
MatDialog,
MatDialogRef,
MatDialogConfig,
MAT_DIALOG_DATA,
MatDialogModule,
} from '@angular/material/dialog';
import {
FormsModule,
ReactiveFormsModule,
UntypedFormGroup,
} from '@angular/forms';
import { CalendarFormDialogComponent } from './calendar-form-dialog/calendar-form-dialog.component';
import {
startOfDay,
subDays,
addDays,
endOfMonth,
isSameDay,
isSameMonth,
addHours,
subMonths,
addMonths,
} from 'date-fns';
import { Subject } from 'rxjs';
import {
CalendarDateFormatter,
CalendarEvent,
CalendarEventAction,
CalendarEventTimesChangedEvent,
CalendarModule,
CalendarView,
} from 'angular-calendar';
import { MaterialModule } from 'src/app/material.module';
import {
MatNativeDateModule,
provideNativeDateAdapter,
} from '@angular/material/core';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatFormFieldModule } from '@angular/material/form-field';
import { TablerIconsModule } from 'angular-tabler-icons';
const colors: any = {
red: {
primary: '#fa896b',
secondary: '#fdede8',
},
blue: {
primary: '#5d87ff',
secondary: '#ecf2ff',
},
yellow: {
primary: '#ffae1f',
secondary: '#fef5e5',
},
};
@Component({
selector: 'app-calendar-dialog',
templateUrl: './dialog.component.html',
imports: [
MaterialModule,
FormsModule,
ReactiveFormsModule,
CommonModule,
MatNativeDateModule,
MatDialogModule,
MatDatepickerModule, TablerIconsModule
],
providers: [provideNativeDateAdapter()],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class CalendarDialogComponent {
options!: UntypedFormGroup;
constructor(
public dialogRef: MatDialogRef<CalendarDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: any
) {}
}
@Component({
selector: 'app-fullcalendar',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './fullcalendar.component.html',
imports: [
MaterialModule,
FormsModule,
ReactiveFormsModule,
NgSwitch,
CalendarModule,
CommonModule,
MatDatepickerModule,
MatDialogModule,
MatFormFieldModule,
],
providers: [provideNativeDateAdapter(), CalendarDateFormatter]
})
export class AppFullcalendarComponent {
dialogRef = signal<MatDialogRef<CalendarDialogComponent> | any>(null);
dialogRef2 = signal<MatDialogRef<CalendarFormDialogComponent> | any>(null);
lastCloseResult = signal<string>('');
actionsAlignment = signal<string>('');
view = signal<any>('month');
viewDate = signal<Date>(new Date());
activeDayIsOpen = signal<boolean>(true);
config: MatDialogConfig = {
disableClose: false,
width: '',
height: '',
position: {
top: '',
bottom: '',
left: '',
right: '',
},
data: {
action: '',
event: [],
},
};
numTemplateOpens = 0;
actions: CalendarEventAction[] = [
{
label: '<span class="text-white link m-l-5">: Edit</span>',
onClick: ({ event }: { event: CalendarEvent }): void => {
this.handleEvent('Edit', event);
},
},
{
label: '<span class="text-danger m-l-5">Delete</span>',
onClick: ({ event }: { event: CalendarEvent }): void => {
this.events.set(
this.events().filter((iEvent: CalendarEvent<any>) => iEvent !== event)
);
this.handleEvent('Deleted', event);
},
},
];
refresh: Subject<any> = new Subject();
events = signal<CalendarEvent[] | any>([
{
start: subDays(startOfDay(new Date()), 1),
end: addDays(new Date(), 1),
title: 'A 3 day event',
color: colors.red,
actions: this.actions,
},
{
start: startOfDay(new Date()),
title: 'An event with no end date',
color: colors.blue,
actions: this.actions,
},
{
start: subDays(endOfMonth(new Date()), 3),
end: addDays(endOfMonth(new Date()), 3),
title: 'A long event that spans 2 months',
color: colors.blue,
},
{
start: addHours(startOfDay(new Date()), 2),
end: new Date(),
title: 'A draggable and resizable event',
color: colors.yellow,
actions: this.actions,
resizable: {
beforeStart: true,
afterEnd: true,
},
draggable: true,
},
]);
constructor(public dialog: MatDialog, @Inject(DOCUMENT) doc: any) {}
dayClicked({ date, events }: { date: Date; events: CalendarEvent[] }): void {
if (isSameMonth(date, this.viewDate())) {
if (
(isSameDay(this.viewDate(), date) && this.activeDayIsOpen() === true) ||
events.length === 0
) {
this.activeDayIsOpen.set(false);
} else {
this.activeDayIsOpen.set(true);
this.viewDate.set(date);
}
}
}
eventTimesChanged({
event,
newStart,
newEnd,
}: CalendarEventTimesChangedEvent): void {
this.events.set(
this.events().map((iEvent: CalendarEvent<any>) => {
if (iEvent === event) {
return {
...event,
start: newStart,
end: newEnd,
};
}
return iEvent;
})
);
this.handleEvent('Dropped or resized', event);
}
handleEvent(action: string, event: CalendarEvent): void {
this.config.data = { event, action };
this.dialogRef.set(this.dialog.open(CalendarDialogComponent, this.config));
this.dialogRef()
.afterClosed()
.subscribe((result: string) => {
this.lastCloseResult.set(result);
this.dialogRef.set(null);
this.refresh.next(result);
});
}
addEvent(): void {
this.dialogRef2.set(
this.dialog.open(CalendarFormDialogComponent, {
panelClass: 'calendar-form-dialog',
autoFocus: false,
data: {
action: 'add',
date: new Date(),
},
})
);
this.dialogRef2()
.afterClosed()
.subscribe((res: { action: any; event: any }) => {
if (!res) {
return;
}
const dialogAction = res.action;
const responseEvent = res.event;
responseEvent.actions = this.actions;
this.events.set([...this.events(), responseEvent]);
this.dialogRef2.set(null);
this.refresh.next(res);
});
}
deleteEvent(eventToDelete: CalendarEvent): void {
this.events.set(
this.events().filter(
(event: CalendarEvent<any>) => event !== eventToDelete
)
);
}
setView(view: CalendarView | any): void {
this.view.set(view);
}
goToPreviousMonth(): void {
this.viewDate.set(subMonths(this.viewDate(), 1));
}
goToNextMonth(): void {
this.viewDate.set(addMonths(this.viewDate(), 1));
}
goToToday() {
this.viewDate.set(new Date());
}
}

View File

@@ -0,0 +1,156 @@
<mat-card class="cardWithShadow">
<mat-card-content>
<form #invoiceForm="ngForm">
<div class="row justify-content-between m-b-24">
<div class="col-sm-4 d-flex align-items-center">
<h4 class="f-s-18 f-w-600">
#
<span name="id" [(ngModel)]="invoice().id" ngDefaultControl>
{{ invoice().id }}</span>
</h4>
</div>
<div class="col-sm-4 text-right">
<a routerLink="/apps/invoice/list" mat-flat-button class="bg-error text-white m-r-10">
Cancel
</a>
<button mat-flat-button color="primary" (click)="saveDetail($event)" [disabled]="addForm.invalid">
Save Invoice
</button>
</div>
</div>
<mat-divider></mat-divider>
<div class="row p-y-24 justify-content-between">
<div class="col-sm-4">
<span class="f-w-600 f-s-15 d-block m-b-8">
Order Status:
</span>
<h6 name="date" class="m-t-5 m-b-0 f-w-500 f-s-14" ngDefaultControl>
{{ invoice().status }}
</h6>
</div>
<div class="col-sm-6 d-flex align-items-center justify-content-end">
<div class="text-right">
<span class="f-w-600 f-s-15 d-block m-b-8">
Order Date
</span>
<h6 name="date" class="m-t-5 m-b-0 f-w-500 f-s-14" [(ngModel)]="invoice().orderDate"
ngDefaultControl>
{{ invoice().orderDate | date : "dd-MM-yyyy" }}
</h6>
</div>
</div>
</div>
<mat-divider></mat-divider>
<div class="row m-y-24 p-t-24">
<div class="col-sm-6">
<mat-form-field appearance="outline" class="w-100">
<mat-label>Bill From</mat-label>
<input matInput placeholder="Bill From" name="from" [(ngModel)]="invoice().billFrom" />
</mat-form-field>
</div>
<div class="col-sm-6">
<mat-form-field appearance="outline" class="w-100">
<mat-label>Bill To</mat-label>
<input matInput placeholder="Bill To" name="to" [(ngModel)]="invoice().billTo" />
</mat-form-field>
</div>
<div class="col-sm-6">
<mat-form-field appearance="outline" class="w-100">
<mat-label>Enter From Address</mat-label>
<input matInput placeholder="Enter From Address" name="fromAddress"
[(ngModel)]="invoice().billFromAddress" />
</mat-form-field>
</div>
<div class="col-sm-6">
<mat-form-field appearance="outline" class="w-100">
<mat-label>Bill From</mat-label>
<input matInput placeholder="Enter To Address" name="toAddress" [(ngModel)]="invoice().billToAddress" />
</mat-form-field>
</div>
</div>
</form>
<div [formGroup]="addForm" class="add-invoice-list">
<div class="table-responsive">
<table class="table table-hover b-1 no-wrap w-100 rounded text-left">
<thead>
<tr>
<th class="p-16">#</th>
<th class="p-16">Item Name</th>
<th class="p-16">Unit Price</th>
<th class="p-16">Units</th>
<th class="p-16">Unit Total Price</th>
<th class="p-16"></th>
</tr>
</thead>
<tbody>
@for(row of addForm.get('rows')['controls']; track row; let index =
$index) {
<tr>
<td class="p-16">
{{ index + 1 }}
</td>
<td class="p-16">
<mat-form-field appearance="outline" class="w-100 hide-hint">
<input type="text" matInput class="form-control" [formControl]="row.get('itemName')"
(input)="itemsChanged()" />
</mat-form-field>
</td>
<td class="p-16">
<mat-form-field appearance="outline" class="w-100 hide-hint">
<input type="number" matInput class="form-control" min="1" [formControl]="row.get('unitPrice')"
(input)="itemsChanged()" />
</mat-form-field>
</td>
<td class="p-16">
<mat-form-field appearance="outline" class="w-100 hide-hint">
<input type="number" matInput class="form-control" min="1" [formControl]="row.get('units')"
(input)="itemsChanged()" />
</mat-form-field>
</td>
<td class="p-16">
<mat-form-field appearance="outline" class="w-100 hide-hint">
<input [disabled]="true" matInput matInput class="form-control" [formControl]="row.get('itemTotal')"
[value]="
row.get('unitPrice').value * row.get('units').value
" />
</mat-form-field>
</td>
<td>
@if(addForm.get('rows')) {
<button (click)="onAddRow()" [disabled]="addForm.invalid" class="d-flex justify-content-center icon-38 p-8" mat-icon-button>
<i-tabler name="circle-plus" class="icon-18 d-flex"></i-tabler>
</button>
}
</td>
<td>
@if(index > 0) {
<button mat-icon-button (click)="onRemoveRow(index)" class="d-flex justify-content-center icon-38 p-8">
<i-tabler name="trash" class="icon-18 d-flex"></i-tabler>
</button>
}
</td>
</tr>
}
</tbody>
</table>
</div>
<div class="text-right m-t-30">
<h5 class="m-b-5 f-w-600 f-s-16">Sub total: {{ subTotal() }}</h5>
<h5 class="f-w-600 f-s-16 m-b-24">Total Vat: {{ vat() }}%</h5>
<mat-divider></mat-divider>
<h3 class="m-b-0 p-t-20 f-s-18">Grand Total: {{ grandTotal() }}</h3>
</div>
</div>
</mat-card-content>
</mat-card>

View File

@@ -0,0 +1,239 @@
<mat-card class="cardWithShadow">
<mat-card-content>
@if( invoice()) {
<span>
<form #invoiceForm="ngForm">
<div class="row m-b-24">
<div class="col-sm-4 d-flex align-items-center">
<h4 class="f-s-14 f-s-18 f-w-600">
#
<span name="id" [(ngModel)]="invoice().id" ngDefaultControl>
{{ invoice().id }}</span
>
</h4>
</div>
<div class="col-sm-8 text-right">
<a
routerLink="/apps/invoice/list"
mat-flat-button
class="bg-error text-white m-r-10"
>
Cancel
</a>
<button
mat-flat-button
color="primary"
(click)="saveDetail($event)"
>
Save Invoice
</button>
</div>
</div>
<mat-divider></mat-divider>
<div class="row p-y-24 justify-content-between">
<div class="col-sm-4">
<span class="f-w-600 f-s-15 d-block m-b-8"> Order Status: </span>
<mat-form-field appearance="outline" class="w-100 theme-select">
<mat-select name="satus" [(ngModel)]="invoice().status">
<mat-option value="Pending"> Pending </mat-option>
<mat-option value="Shipped"> Shipped </mat-option>
<mat-option value="Delivered"> Delivered </mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="col-sm-6 d-flex align-items-center justify-content-end">
<div class="text-right">
<span class="f-w-600 f-s-15 d-block m-b-8"> Order Date </span>
<h6
name="date"
class="m-t-5 m-b-0 f-w-500 f-s-14 f-s-16"
[(ngModel)]="invoice().orderDate"
ngDefaultControl
>
{{ invoice().orderDate | date : "dd-MM-yyyy" }}
</h6>
</div>
</div>
</div>
<mat-divider></mat-divider>
<div class="row m-y-24 p-t-24">
<div class="col-sm-6">
<mat-form-field appearance="outline" class="w-100">
<mat-label>Bill From</mat-label>
<input
matInput
placeholder="Bill From"
name="from"
[(ngModel)]="invoice().billFrom"
/>
</mat-form-field>
</div>
<div class="col-sm-6">
<mat-form-field appearance="outline" class="w-100">
<mat-label>Bill To</mat-label>
<input
matInput
placeholder="Bill To"
name="to"
[(ngModel)]="invoice().billTo"
/>
</mat-form-field>
</div>
<div class="col-sm-6">
<mat-form-field appearance="outline" class="w-100">
<mat-label>Enter From Address</mat-label>
<input
matInput
placeholder="Enter From Address"
name="fromAddress"
[(ngModel)]="invoice().billFromAddress"
/>
</mat-form-field>
</div>
<div class="col-sm-6">
<mat-form-field appearance="outline" class="w-100">
<mat-label>Bill From</mat-label>
<input
matInput
placeholder="Enter To Address"
name="toAddress"
[(ngModel)]="invoice().billToAddress"
/>
</mat-form-field>
</div>
</div>
</form>
</span>
}
<form [formGroup]="addForm" class="edit-invoice-list">
<div class="table-responsive">
<table
id="tblAdd"
class="table table-hover b-1 no-wrap w-100 rounded text-left"
>
<thead>
<tr>
<th class="p-16">#</th>
<th class="p-16">Item Name</th>
<th class="p-16">Unit Price</th>
<th class="p-16">Units</th>
<th class="p-16">Unit Total Price</th>
<th class="p-16"></th>
</tr>
</thead>
@for(a of addForm.get('item')['controls']; track a; let i =$index) {
<tbody formArrayName="item">
<tr [formGroupName]="i">
<td class="p-16">
{{ i + 1 }}
</td>
<td class="p-16">
<mat-form-field appearance="outline" class="w-100 hide-hint">
<input
matInput
type="text"
[id]="'txtNameControl' + i"
class="form-control"
placeholder="Enter Item Name"
formControlName="itemName"
(input)="itemsChanged()"
/>
</mat-form-field>
</td>
<td class="p-16">
<mat-form-field appearance="outline" class="w-100 hide-hint">
<input
matInput
type="number"
[id]="'txtCostControl' + i"
class="form-control"
placeholder="Enter Item Price"
formControlName="itemCost"
(input)="itemsChanged()"
/>
</mat-form-field>
</td>
<td class="p-16">
<mat-form-field appearance="outline" class="w-100 hide-hint">
<input
matInput
type="number"
[id]="'txtTotalControl' + i"
class="form-control"
placeholder="Enter Item"
formControlName="itemSold"
(input)="itemsChanged()"
/>
</mat-form-field>
</td>
<td class="p-16">
<mat-form-field appearance="outline" class="w-100 hide-hint">
<input
matInput
type="number"
formControlName="itemTotal"
[id]="'txtitemTotalControl' + i"
[value]="
(addForm.get('item')?.value[i]?.itemCost || 0) *
(addForm.get('item')?.value[i]?.itemSold || 0)
"
class="form-control"
[disabled]="true"
/>
</mat-form-field>
</td>
<td>
<button
mat-icon-button
color="primary"
(click)="btnAddItemClick()"
class="d-flex justify-content-center icon-38 p-8"
[disabled]="addForm.get('item')?.invalid"
>
<i-tabler
name="circle-plus"
class="icon-18 d-flex"
></i-tabler>
</button>
</td>
<td>
@if(addForm.get('item')?.length > 1) {
<button
mat-icon-button
(click)="btnRemoveClick(i)"
class="d-flex justify-content-center icon-38 p-8"
>
<i-tabler name="trash" class="icon-18 d-flex"></i-tabler>
</button>
}
</td>
</tr>
</tbody>
}
</table>
</div>
<div class="text-right m-t-30">
<div class="text-right m-t-30">
@if(addForm.get('rows')) {
<button color="accent" mat-flat-button [disabled]="addForm.invalid">
Add row
</button>
}
<h5 class="m-b-5 f-w-600 f-s-16">Sub total: {{ subTotal() }}</h5>
<h5 class="f-w-600 f-s-16 m-b-24">Total Vat: {{ vat() }}%</h5>
<mat-divider></mat-divider>
<h3 class="m-b-0 p-t-20 f-s-18">Grand Total: {{ grandTotal() }}</h3>
</div>
</div>
</form>
</mat-card-content>
</mat-card>

View File

@@ -0,0 +1,164 @@
import { Component, signal } from '@angular/core';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import { InvoiceService } from 'src/app/services/apps/invoice/invoice.service';
import { InvoiceList, order } from '../invoice';
import {
UntypedFormGroup,
UntypedFormArray,
UntypedFormBuilder,
Validators,
FormsModule,
ReactiveFormsModule,
} from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { OkDialogComponent } from './ok-dialog/ok-dialog.component';
import { MaterialModule } from 'src/app/material.module';
import { CommonModule } from '@angular/common';
import { TablerIconsModule } from 'angular-tabler-icons';
import { MatSnackBar } from '@angular/material/snack-bar';
@Component({
selector: 'app-edit-invoice',
templateUrl: './edit-invoice.component.html',
imports: [
MaterialModule,
CommonModule,
RouterLink,
FormsModule,
ReactiveFormsModule,
TablerIconsModule,
],
})
export class AppEditInvoiceComponent {
id = signal<any>(null);
subTotal = signal<number>(0);
vat = signal<number>(0);
grandTotal = signal<number>(0);
addForm: UntypedFormGroup | any;
invoice = signal<InvoiceList | any>([]);
constructor(
activatedRouter: ActivatedRoute,
private invoiceService: InvoiceService,
private router: Router,
private fb: UntypedFormBuilder,
public dialog: MatDialog,
private snackBar: MatSnackBar
) {
this.id.set(activatedRouter.snapshot.paramMap.get('id'));
this.loadInvoice(); // Load invoice here
this.subTotal.set(this.invoice()?.totalCost || 0);
this.vat.set(this.invoice()?.vat || 0);
this.grandTotal.set(this.invoice()?.grandTotal || 0);
this.addForm = this.fb.group({
item: this.fb.array([this.itemControl()]),
});
this.fillAddControls();
}
loadInvoice(): void {
const invoiceData = this.invoiceService
.getInvoiceList()
.find((x) => x.id === +this.id());
this.invoice.set(invoiceData); // Set the invoice signal
}
itemControl(): UntypedFormGroup {
return this.fb.group({
itemName: ['', Validators.required],
itemCost: ['', Validators.required],
itemSold: ['', Validators.required],
itemTotal: [{ value: 0, disabled: true }],
});
}
fillAddControls(): void {
this.addForm.setControl('item', this.setItem(this.invoice()?.orders));
}
setItem(order: any): UntypedFormArray {
const fa = new UntypedFormArray([]);
order?.forEach((s: any) => {
fa.push(
this.fb.group({
itemName: s.itemName,
itemCost: s.unitPrice,
itemSold: s.units,
itemTotal: s.unitTotalPrice,
})
);
});
return fa;
}
btnAddItemClick(): void {
(<UntypedFormArray>this.addForm.get('item')).push(this.itemControl());
}
btnRemoveClick(i: number): void {
const totalCostOfItem =
this.addForm.get('item')?.value[i].itemCost *
this.addForm.get('item')?.value[i].itemSold;
this.subTotal.set(this.subTotal() - totalCostOfItem);
this.vat.set(this.subTotal() / 10);
this.grandTotal.set(this.subTotal() + this.vat());
(<UntypedFormArray>this.addForm.get('item')).removeAt(i);
}
itemsChanged(): void {
let total = 0;
for (
let t = 0;
t < (<UntypedFormArray>this.addForm.get('item')).length;
t++
) {
if (
this.addForm.get('item')?.value[t].itemCost != '' &&
this.addForm.get('item')?.value[t].itemSold
) {
total +=
this.addForm.get('item')?.value[t].itemCost *
this.addForm.get('item')?.value[t].itemSold;
}
}
this.subTotal.set(total);
this.vat.set(this.subTotal() / 10);
this.grandTotal.set(this.subTotal() + this.vat());
}
saveDetail(event: Event): void {
event.preventDefault();
const currentInvoice = this.invoice();
if (currentInvoice) {
currentInvoice.grandTotal = this.grandTotal();
currentInvoice.totalCost = this.subTotal();
currentInvoice.vat = this.vat();
currentInvoice.orders = [];
for (
let t = 0;
t < (<UntypedFormArray>this.addForm.get('item')).length;
t++
) {
const o: order = new order();
o.itemName = this.addForm.get('item')?.value[t].itemName;
o.unitPrice = this.addForm.get('item')?.value[t].itemCost;
o.units = this.addForm.get('item')?.value[t].itemSold;
o.unitTotalPrice = o.units * o.unitPrice;
currentInvoice.orders.push(o);
}
this.dialog.open(OkDialogComponent);
this.invoiceService.updateInvoice(currentInvoice.id, currentInvoice);
this.router.navigate(['/apps/invoice/list']);
this.showSnackbar('Invoice updated successfully!');
}
}
showSnackbar(message: string): void {
this.snackBar.open(message, 'Close', {
duration: 3000,
horizontalPosition: 'center',
verticalPosition: 'top',
});
}
}

View File

@@ -0,0 +1,281 @@
<div class="row">
<div class="col-sm-6 col-lg-3">
<mat-card
class="cardWithShadow cursor-pointer bg-light-primary shadow-none"
[ngClass]="{ 'active-tab': activeTab() === 'All' }"
(click)="handleTabClick('All')"
>
<mat-card-content class="d-flex align-items-center gap-16">
<div
class="icon icon-38 rounded d-flex align-items-center justify-content-center bg-primary text-white"
>
<i-tabler name="list-details" class="icon-24 d-flex"></i-tabler>
</div>
<div class="info">
<h5 class="f-w-400 lh-sm f-s-14">Total</h5>
<h5 class="f-w-500 lh-sm f-s-14">
{{ allInvoices().length }} invoices
</h5>
</div>
</mat-card-content>
</mat-card>
</div>
<div class="col-sm-6 col-lg-3">
<mat-card
class="cardWithShadow cursor-pointer bg-light-secondary shadow-none"
[ngClass]="{ 'active-tab': activeTab() === 'Shipped' }"
(click)="handleTabClick('Shipped')"
>
<mat-card-content class="d-flex align-items-center gap-16">
<div
class="icon icon-38 rounded d-flex align-items-center justify-content-center bg-secondary text-white"
>
<i-tabler name="shopping-bag" class="icon-24 d-flex"></i-tabler>
</div>
<div class="info">
<h5 class="f-w-400 lh-sm f-s-14">Shipped</h5>
<h5 class="f-w-500 lh-sm f-s-14">
{{ countInvoicesByStatus("Shipped") }} invoices
</h5>
</div>
</mat-card-content>
</mat-card>
</div>
<div class="col-sm-6 col-lg-3">
<mat-card
class="cardWithShadow cursor-pointer bg-light-success shadow-none"
[ngClass]="{ 'active-tab': activeTab() === 'Delivered' }"
(click)="handleTabClick('Delivered')"
>
<mat-card-content class="d-flex align-items-center gap-16">
<div
class="icon icon-38 rounded d-flex align-items-center justify-content-center bg-success text-white"
>
<i-tabler name="truck" class="icon-24 d-flex"></i-tabler>
</div>
<div class="info">
<h5 class="f-w-400 lh-sm f-s-14">Delivered</h5>
<h5 class="f-w-500 lh-sm f-s-14">
{{ countInvoicesByStatus("Delivered") }} invoices
</h5>
</div>
</mat-card-content>
</mat-card>
</div>
<div class="col-sm-6 col-lg-3">
<mat-card
class="cardWithShadow cursor-pointer bg-light-warning shadow-none"
[ngClass]="{ 'active-tab': activeTab() === 'Pending' }"
(click)="handleTabClick('Pending')"
>
<mat-card-content class="d-flex align-items-center gap-16">
<div
class="icon icon-38 rounded d-flex align-items-center justify-content-center bg-warning text-white"
>
<i-tabler name="sort-ascending" class="icon-24 d-flex"></i-tabler>
</div>
<div class="info">
<h5 class="f-w-400 lh-sm f-s-14">Pending</h5>
<h5 class="f-w-500 lh-sm f-s-14">
{{ countInvoicesByStatus("Pending") }} invoices
</h5>
</div>
</mat-card-content>
</mat-card>
</div>
</div>
<mat-card class="cardWithShadow">
<mat-card-content>
<div class="row justify-content-between align-items-center">
<div class="col-sm-4">
<mat-form-field appearance="outline" class="w-100 hide-hint">
<input
matInput
placeholder="Search Invoice"
(keyup)="filter($any($event.target).value)"
/>
<mat-icon matSuffix>
<i-tabler name="search" class="icon-20 d-flex m-t-4"></i-tabler>
</mat-icon>
</mat-form-field>
</div>
<div class="col-sm-4 d-flex align-items-center justify-content-end">
<a
mat-button
[routerLink]="['/apps/invoice/addInvoice']"
mat-flat-button
color="primary"
>Add Invoice</a
>
</div>
</div>
</mat-card-content>
</mat-card>
<mat-card class="cardWithShadow">
<mat-card-content>
<div class="table-responsive">
<table
mat-table
[dataSource]="invoiceList"
matSort
class="no-wrap m-t-0 v-middle w-100"
>
<ng-container matColumnDef="chk">
<th mat-header-cell *matHeaderCellDef>
<mat-checkbox
[checked]="allComplete()"
[indeterminate]="someComplete()"
(change)="setAll($event.checked)"
color="primary"
>
</mat-checkbox>
</th>
<td mat-cell *matCellDef="let element" class="f-s-14">
<mat-checkbox
[(ngModel)]="element.completed"
(ngModelChange)="updateAllComplete()"
color="primary"
>
</mat-checkbox>
</td>
</ng-container>
<ng-container matColumnDef="id">
<th
mat-header-cell
*matHeaderCellDef
mat-sort-header
class="f-w-600 f-s-15"
>
Id
</th>
<td mat-cell *matCellDef="let element" class="f-s-14">
{{ element.id }}
</td>
</ng-container>
<ng-container matColumnDef="billFrom">
<th
mat-header-cell
*matHeaderCellDef
mat-sort-header
class="f-w-600 f-s-15"
>
Bill From
</th>
<td mat-cell *matCellDef="let element" class="f-s-14">
{{ element.billFrom }}
</td>
</ng-container>
<ng-container matColumnDef="billTo">
<th
mat-header-cell
*matHeaderCellDef
mat-sort-header
class="f-w-600 f-s-15"
>
Bill To
</th>
<td mat-cell *matCellDef="let element" class="f-s-14">
{{ element.billTo }}
</td>
</ng-container>
<ng-container matColumnDef="totalCost">
<th
mat-header-cell
*matHeaderCellDef
mat-sort-header
class="f-w-600 f-s-15"
>
Total Cost
</th>
<td mat-cell *matCellDef="let element" class="f-s-14">
{{ element.totalCost }}
</td>
</ng-container>
<ng-container matColumnDef="status">
<th
mat-header-cell
*matHeaderCellDef
mat-sort-header
class="f-w-600 f-s-15"
>
Status
</th>
<td mat-cell *matCellDef="let element" class="f-s-14">
<span
class="p-x-8 p-y-4 f-w-500 rounded-pill f-s-12"
[ngStyle]="{
'background-color':
element.status === 'Shipped'
? 'rgb(93, 135, 255)'
: element.status === 'Delivered'
? 'rgb(19, 222, 185)'
: element.status === 'Pending'
? 'rgb(255, 174, 31)'
: 'transparent',
color: 'white'
}"
>
{{ element.status }}
</span>
</td>
</ng-container>
<ng-container matColumnDef="action">
<th mat-header-cell *matHeaderCellDef class="f-w-600 f-s-15">
Action
</th>
<td mat-cell *matCellDef="let element" class="d-flex">
<a
mat-icon-button
[routerLink]="['/apps/invoice/editinvoice', element.id]"
class="d-flex align-items-center justify-content-center"
>
<i-tabler
name="pencil"
class="icon-18 d-flex align-items-center"
></i-tabler>
</a>
<a
mat-icon-button
[routerLink]="['/apps/invoice/viewInvoice', element.id]"
class="d-flex align-items-center justify-content-center"
>
<i-tabler
name="eye"
class="icon-18 d-flex align-items-center"
></i-tabler>
</a>
<a
mat-icon-button
(click)="deleteInvoice(element.id)"
class="d-flex align-items-center justify-content-center"
>
<i-tabler
name="trash"
class="icon-18 d-flex align-items-center"
></i-tabler>
</a>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>
<mat-paginator
[pageSizeOptions]="[5, 8, 10]"
showFirstLastButtons
></mat-paginator>
</div>
</mat-card-content>
</mat-card>

View File

@@ -0,0 +1,125 @@
<mat-card class="cardWithShadow">
<mat-card-content>
@if(invoiceDetail()){
<span>
<div class="row m-b-24">
<div class="col-sm-4 d-flex align-items-center">
<h4 class="f-s-14 f-s-18 f-w-600">#{{ invoiceDetail()?.id }}</h4>
</div>
<div class="col-sm-8 text-right">
<a routerLink="/apps/invoice/list" mat-stroked-button class="m-r-10"
>Back to Invoice</a
>
<a
[routerLink]="['/apps/invoice/editinvoice/', invoiceDetail()?.id]"
mat-flat-button
>Edit Invoice</a
>
</div>
</div>
<mat-divider></mat-divider>
<div class="row p-y-24">
<div class="col-sm-6">
<span class="f-w-600 f-s-15"> Order Status: </span>
<h6 class="m-t-5 m-b-0 f-w-500 f-s-14">
{{ invoiceDetail()?.status }}
</h6>
</div>
<div class="col-sm-6 text-right">
<span class="f-w-600 f-s-15"> Order Date: </span>
<h6 class="m-t-5 m-b-0 f-w-500 f-s-14">
{{ invoiceDetail()?.orderDate | date : "fullDate" }}
</h6>
</div>
</div>
<mat-divider></mat-divider>
<div class="row p-y-24">
<div class="col-sm-6">
<span class="f-w-600 f-s-15"> Bill From: </span>
<h6 class="m-t-5 m-b-0 f-w-500 f-s-14">
{{ invoiceDetail()?.billFrom }}
</h6>
<h6 class="m-t-5 m-b-0 f-w-500 f-s-14">
{{ invoiceDetail()?.billFromEmail }}
</h6>
<h6 class="m-t-5 m-b-0 f-w-500 f-s-14">
{{ invoiceDetail()?.billFromAddress }}
</h6>
<h6 class="m-t-5 m-b-0 f-w-500 f-s-14">
{{ invoiceDetail()?.billFromPhone }}
</h6>
</div>
<div class="col-sm-6 text-right">
<span class="f-w-600 f-s-15"> Bill To: </span>
<h6 class="m-t-5 m-b-0 f-w-500 f-s-14">
{{ invoiceDetail()?.billTo }}
</h6>
<h6 class="m-t-5 m-b-0 f-w-500 f-s-14">
{{ invoiceDetail()?.billToEmail }}
</h6>
<h6 class="m-t-5 m-b-0 f-w-500 f-s-14">
{{ invoiceDetail()?.billToAddress }}
</h6>
<h6 class="m-t-5 m-b-0 f-w-500 f-s-14">
{{ invoiceDetail()?.billToPhone }}
</h6>
</div>
</div>
<div class="b-1 table-responsive">
<table
mat-table
[dataSource]="invoiceDetail()?.orders || []"
class="no-wrap v-middle"
>
<ng-container matColumnDef="itemName">
<th mat-header-cell *matHeaderCellDef class="f-s-15 f-w-600">
Item Name
</th>
<td class="font-normal" mat-cell *matCellDef="let element">
{{ element.itemName }}
</td>
</ng-container>
<ng-container matColumnDef="unitPrice">
<th mat-header-cell *matHeaderCellDef class="f-s-15 f-w-600">
Unit Price
</th>
<td class="font-normal" mat-cell *matCellDef="let element">
{{ element.unitPrice }}
</td>
</ng-container>
<ng-container matColumnDef="unit">
<th mat-header-cell *matHeaderCellDef class="f-s-15 f-w-600">
Unit
</th>
<td class="font-normal" mat-cell *matCellDef="let element">
{{ element.units }}
</td>
</ng-container>
<ng-container matColumnDef="total">
<th mat-header-cell *matHeaderCellDef class="f-s-15 f-w-600">
Total Cost
</th>
<td class="font-normal" mat-cell *matCellDef="let element">
{{ element.unitTotalPrice }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>
</div>
<div class="text-right m-t-30">
<h5 class="m-b-5 f-w-600 f-s-16">
Sub total: {{ invoiceDetail()?.totalCost }}
</h5>
<span class="f-w-600 f-s-16">Vat: 10%</span>
<h3 class="m-b-0 b-t-1 p-t-20 f-s-18 m-t-24">
Grand Total: {{ invoiceDetail()?.grandTotal }}
</h3>
</div>
</span>
}
</mat-card-content>
</mat-card>

View File

@@ -0,0 +1,132 @@
@if(action !== 'Delete') {
<mat-dialog-content class="mat-typography">
<div class="d-flex align-items-center justify-content-between m-b-16">
<h3>{{action}} Ticket</h3>
<button
mat-icon-button
mat-dialog-close
class="d-flex justify-content-center"
>
<i-tabler name="x" class="icon-20 d-flex"></i-tabler>
</button>
</div>
<form #userForm="ngForm">
<div class="row">
@if(action === 'Update') {
<div class="col-sm-6 col-lg-12">
<mat-label class="f-s-14 f-w-600 m-b-8 d-block">Ticket Id</mat-label>
<mat-form-field appearance="outline" class="w-100">
<input
type="text"
matInput
required
id="id"
name="id"
[(ngModel)]="local_data.id"
placeholder="id"
/>
</mat-form-field>
</div>
}
<div class="col-sm-6 col-lg-12">
<mat-label class="f-s-14 f-w-600 m-b-8 d-block">Ticket Title</mat-label>
<mat-form-field appearance="outline" class="w-100">
<input
type="text"
matInput
required
id="title"
name="title"
[(ngModel)]="local_data.title"
placeholder="Ticker Title"
/>
</mat-form-field>
</div>
<div class="col-sm-6 col-lg-12">
<mat-label class="f-s-14 f-w-600 m-b-8 d-block"
>Ticket Subtext</mat-label
>
<mat-form-field appearance="outline" class="w-100">
<input
type="text"
matInput
required
id="subtext"
name="subtext"
[(ngModel)]="local_data.subtext"
placeholder="Ticket Subtext"
/>
</mat-form-field>
</div>
<div class="col-sm-6 col-lg-12">
<mat-label class="f-s-14 f-w-600 m-b-8 d-block">Assign User</mat-label>
<mat-form-field appearance="outline" class="w-100">
<mat-select
placeholder="Assign User"
[(ngModel)]="local_data.assignee"
name="assignee"
required
>
@for(user of users; track trackByUser(user)) {
<mat-option [value]="user.name">
<div class="d-flex align-items-center gap-8">
<img
[src]="user.photo"
alt="{{ user.name }}"
style="width: 24px; height: 24px; border-radius: 50%"
/>
{{ user.name }}
</div>
</mat-option>
}
</mat-select>
</mat-form-field>
</div>
@if(action === 'Update'){
<div class="col-sm-6 col-lg-12">
<mat-label class="f-s-14 f-w-600 m-b-8 d-block">Status</mat-label>
<mat-form-field appearance="outline" class="w-100">
<select
matNativeControl
required
name="status"
[(ngModel)]="local_data.status"
>
<option value="inprogress">In Progress</option>
<option value="open">Open</option>
<option value="closed">Closed</option>
</select>
</mat-form-field>
</div>
} @if(action === 'Update') {
<div class="col-sm-6 col-lg-12">
<mat-form-field>
<mat-label>Date</mat-label>
<input
matInput
[matDatepicker]="picker1"
[formControl]="dateControl"
/>
<mat-datepicker-toggle
matIconSuffix
[for]="picker1"
></mat-datepicker-toggle>
<mat-datepicker #picker1></mat-datepicker>
</mat-form-field>
</div>
}
</div>
</form>
</mat-dialog-content>
} @else {
<div class="p-x-24 p-b-24">
Sure to delete <span class="f-w-600">{{local_data.title}}</span>?
</div>
}
<div mat-dialog-actions class="p-24 p-t-0">
<button mat-flat-button (click)="doAction()">{{action}}</button>
<button mat-flat-button class="bg-error text-white" (click)="closeDialog()">
Cancel
</button>
</div>

View File

@@ -0,0 +1,177 @@
import {
Component,
OnInit,
ViewChild,
AfterViewInit,
Inject,
} from '@angular/core';
import { MatTableDataSource, MatTable } from '@angular/material/table';
import {
MatDialog,
MatDialogRef,
MAT_DIALOG_DATA,
} from '@angular/material/dialog';
import { MatPaginator } from '@angular/material/paginator';
import { MaterialModule } from 'src/app/material.module';
import { CommonModule } from '@angular/common';
import { TablerIconsModule } from 'angular-tabler-icons';
import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { TicketService } from 'src/app/services/apps/ticket/ticket.service';
import { TicketElement } from 'src/app/pages/apps/tickets/ticket';
import { MatSnackBar } from '@angular/material/snack-bar';
@Component({
selector: 'app-ticket-list',
templateUrl: './tickets.component.html',
imports: [MaterialModule, CommonModule, TablerIconsModule],
})
export class AppTicketlistComponent implements OnInit, AfterViewInit {
@ViewChild(MatTable, { static: true }) table: MatTable<any>;
@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
searchText: string = '';
totalCount = 0;
Closed = 0;
Inprogress = 0;
Open = 0;
displayedColumns: string[] = [
'id',
'title',
'assignee',
'status',
'date',
'action',
];
dataSource = new MatTableDataSource<TicketElement>([]);
constructor(private ticketService: TicketService, public dialog: MatDialog) {}
ngOnInit(): void {
this.loadTickets(); // Load the initial tickets
}
private loadTickets(): void {
const tickets = this.ticketService.tickets$; // Get tickets from the service
this.dataSource.data = tickets; // Set the dataSource to the tickets
// Update counts based on the current tickets
this.updateCounts();
}
private updateCounts(): void {
this.totalCount = this.dataSource.data.length;
this.Open = this.countTicketsByStatus('open');
this.Closed = this.countTicketsByStatus('closed');
this.Inprogress = this.countTicketsByStatus('inprogress');
}
ngAfterViewInit(): void {
this.dataSource.paginator = this.paginator;
}
onKeyup(event: KeyboardEvent): void {
const input = event.target as HTMLInputElement;
this.applyFilter(input.value);
}
applyFilter(filterValue: string): void {
this.dataSource.filter = filterValue.trim().toLowerCase();
}
btnCategoryClick(val: string): number {
this.dataSource.filter = val.trim().toLowerCase();
return this.dataSource.filteredData.length;
}
openDialog(action: string, ticket: TicketElement | any): void {
const dialogRef = this.dialog.open(TicketDialogComponent, {
data: { action, ticket },
autoFocus: false,
});
dialogRef.afterClosed().subscribe(() => {
this.loadTickets();
});
}
countTicketsByStatus(status: string): number {
return this.dataSource.data.filter(
(ticket) => ticket.status.toLowerCase() === status.toLowerCase()
).length;
}
}
@Component({
// tslint:disable-next-line - Disables all
selector: 'app-dialog-content',
templateUrl: 'ticket-dialog-content.html',
imports: [
MaterialModule,
CommonModule,
TablerIconsModule,
FormsModule,
ReactiveFormsModule,
TablerIconsModule,
],
})
export class TicketDialogComponent {
action: string;
local_data: TicketElement;
users: any[] = [];
dateControl = new FormControl();
constructor(
public dialogRef: MatDialogRef<TicketDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: any,
private ticketService: TicketService,
private snackBar: MatSnackBar
) {
this.action = data.action;
this.local_data = { ...data.ticket };
}
ngOnInit(): void {
this.users = this.ticketService.getUsers(); // Get users from the service
if (this.local_data.date) {
this.dateControl.setValue(
new Date(this.local_data.date).toISOString().split('T')[0]
); // existing date
} else {
// Set to today's date if no existing date is available
this.dateControl.setValue(new Date().toISOString().split('T')[0]);
}
}
doAction(): void {
this.local_data.date = this.dateControl.value; // Update local_data with the new date
if (this.action === 'Update') {
this.ticketService.updateTicket(this.local_data);
this.openSnackBar('Ticket updated successfully!', 'Close');
} else if (this.action === 'Add') {
this.ticketService.addTicket(this.local_data);
this.openSnackBar('Ticket added successfully!', 'Close');
} else if (this.action === 'Delete') {
this.ticketService.deleteTicket(this.local_data.id);
this.openSnackBar('Ticket deleted successfully!', 'Close');
}
this.dialogRef.close();
}
openSnackBar(message: string, action: string): void {
this.snackBar.open(message, action, {
duration: 3000,
horizontalPosition: 'center',
verticalPosition: 'top',
});
}
closeDialog(): void {
this.dialogRef.close();
}
trackByUser(user: any): any {
return user.id;
}
}

View File

@@ -0,0 +1,169 @@
<div class="contact-page">
<div class="banner-section bg-light-primary contact-herder spacing-top-bottom">
<div class="container p-y-20">
<div class="row align-items-center">
<div class="col-lg-6">
<h1 class="m-b-24 f-s-48 lh-normal section-sub-title">
Get to know Modernize Dashboard Template
</h1>
<div class="hstack">
<a mat-flat-button color="primary">Create an account</a>
<a mat-stroked-button color="primary" class="border-primary">View Open
Positions</a>
</div>
</div>
<div class="col-lg-6">
<p class="lh-base m-t-32">
Do you need a highly customizable and developer friendly premium
Angular admin template packed with numerous features? Modernize
Angular Admin Template has everything you need. This bootstrap based
admin template is designed in accordance with industry standards and
best practices to provide you.
</p>
</div>
</div>
</div>
</div>
<div class="spacing-top-bottom setup-process">
<div class="container">
<h2 class="text-center section-sub-title m-b-48 f-s-40 lh-normal">
The hassle-free setup process
</h2>
<div class="row">
@for(topcard of setupCards; track topcard.title) {
<div class="col-lg-3 col-sm-6 d-flex align-items-stretch">
<mat-card class="shadow-none text-center w-100 bg-light-{{
topcard.color
}} rounded-8 ">
<mat-card-content>
<div class="m-t-16">
@if(topcard.id!==2){
<img [src]="topcard.img" alt="users" width="40" class="rounded-circle" />
}
<h6 class="f-s-16 m-t-16">
{{ topcard.title }}
</h6>
<p class="f-s-14 m-t-16 m-b-0">
{{ topcard.subtitle }}
</p>
@if(topcard.id===2){
<img [src]="topcard.imgMain" alt="image" class="img-fluid w-100 m-t-10 m-b--32" />
}
</div>
</mat-card-content>
</mat-card>
</div>
}
</div>
</div>
</div>
<mat-divider></mat-divider>
<div class="spacing-top-bottom key-metric">
<div class="container">
<div class="row justify-content-between">
<div class="col-md-5">
<div class="m-b-32">
<h2 class="f-s-40 m-b-16 section-sub-title f-s-40 lh-normal">Key metric at a glance</h2>
<p class="f-s-14 m-0 lh-base">
From the year we were founded to the impressive customer base
we've built, and the growth percentages that reflect our
continuous improvement, these numbers tell our story at a glance.
Explore the data that drives our mission and underscores our
commitment to excellence.
</p>
</div>
</div>
<div class="col-md-6">
<div class="row stat-section">
@for (stat of stats; track stat) {
<div class="col-6 m-b-32">
<div class="stat-block">
<p class="stat-label f-s-12 f-w-400 text-uppercase text-primary m-y-0">
{{ stat.label }}
</p>
<h2 class="stat-value f-s-48 lh-normal section-sub-title">
{{ stat.value }}
</h2>
<p class="f-s-14 m-y-0">{{ stat.description }}</p>
</div>
</div>
}
</div>
</div>
</div>
</div>
</div>
<div class="our-leadership spacing-top p-b-48">
<app-image-slider></app-image-slider>
</div>
<div class="features spacing-bottom">
<div class="container">
<div class="row align-items-center justify-content-between">
<!--row-->
<div class="col-md-5 m-b-30">
<div class="client-margin">
<h2 class="lh-normal f-s-40 m-b-16 section-sub-title">
What our clients <br> think <img src="assets/images/front-pages/logoIcon.svg" alt="logo" />
about us?
</h2>
<p class="m-0">
Our users' feedback is a testament to our commitment to quality
and user satisfaction. Read what they have to say about their
journey with us.
</p>
</div>
</div>
<div class="col-md-5">
<mat-card class="cardWithShadow b-1 rounded-8 m-b-0 p-48">
<mat-card-content>
<mat-card-title class="f-s-24 f-w-600 m-b-24">Features availability</mat-card-title>
<div class="d-flex align-items-center gap-16 m-b-24">
<div>
<img [src]="currentUser().img" [alt]="currentUser().name" class="rounded-circle" width="40" />
</div>
<h6 class="f-s-14 f-w-600">{{ currentUser().name }}</h6>
</div>
<p class="f-s-14 m-b-16 m-t-0">
Our users' feedback is a testament to our commitment to quality
and user satisfaction. Read what they have to say about their
journey with us.
</p>
<mat-divider></mat-divider>
<div class="d-flex align-items-center gap-10 m-t-8">
<button class="bg-light icon-32 d-flex align-items-center justify-content-center" mat-icon-button
(click)="goPrev()">
<i-tabler name="chevron-left"
class="icon-18 d-flex align-items-center justify-content-center"></i-tabler>
</button>
<span class="f-s-14">{{ displayCount() }}</span>
<button class="bg-light icon-32 d-flex align-items-center justify-content-center" mat-icon-button
(click)="goNext()">
<i-tabler name="chevron-right"
class="icon-18 d-flex align-items-center justify-content-center"></i-tabler>
</button>
</div>
</mat-card-content>
</mat-card>
</div>
</div>
</div>
</div>
<div class="footer">
<app-footer></app-footer>
</div>
</div>

View File

@@ -0,0 +1,23 @@
.contact-page {
.setup-process {
mat-card-content {
padding: 0px !important;
padding: 30px 16px !important;
}
}
.key-metric {
box-shadow: 0px 6px 12px rgba(127, 145, 156, 0.12);
}
.features {
.cardWithShadow {
mat-card-content {
padding: 0px !important;
}
}
}
}

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AboutUsComponent } from './about-us.component';
describe('AboutUsComponent', () => {
let component: AboutUsComponent;
let fixture: ComponentFixture<AboutUsComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [AboutUsComponent]
})
.compileComponents();
fixture = TestBed.createComponent(AboutUsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,48 @@
import { Component, computed, signal } from '@angular/core';
import { IconModule } from 'src/app/icon/icon.module';
import { MaterialModule } from 'src/app/material.module';
import { ImageSliderComponent } from '../image-slider/image-slider.component';
import { FooterComponent } from '../footer/footer.component';
//import { PagePricingComponent } from '../page-pricing/page-pricing.component';
import {
setupCards,
stats,
users,
} from '../front-pagesData';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-about-us',
imports: [IconModule,MaterialModule ,CommonModule,ImageSliderComponent,FooterComponent,
//PagePricingComponent
],
templateUrl: './about-us.component.html',
styleUrl: './about-us.component.scss'
})
export class AboutUsComponent {
setupCards=setupCards;
stats = stats;
currentIndex = signal(0); // Starting from 0
users = users;
// Computed values to auto-update template
currentUser = computed(() => this.users[this.currentIndex()]);
displayCount = computed(
() => `${this.currentIndex() + 1}/${this.users.length}`
);
goPrev() {
if (this.currentIndex() > 0) {
this.currentIndex.update((i) => i - 1);
}
}
goNext() {
if (this.currentIndex() < this.users.length - 1) {
this.currentIndex.update((i) => i + 1);
}
}
}

View File

@@ -0,0 +1,116 @@
<div class="banner-section bg-light-primary spacing-top-bottom">
<div class="container">
<p class="text-primary text-center text-uppercase f-s-14 m-t-0">
Blog Page
</p>
<h1 class="text-center f-s-48 section-sub-title lh-normal">Latest blog & news</h1>
</div>
</div>
<div class="blog-details-content spacing-top-bottom">
<div class="container">
<!-- ----------------------------------------------------------------- -->
<!-- If Blog is available -->
<!-- ----------------------------------------------------------------- -->
@if(blogDetail()) {
<mat-card class="cardWithShadow">
<img mat-card-image src="{{ blogDetail()?.imgSrc }}" alt="Photo of a Shiba Inu" height="440" />
<div class="detail-card-overlay h-100 d-flex align-items-end justify-content-end">
<span class="f-s-12 m-y-16 f-w-600 bg-white rounded-pill p-x-8 m-r-16">2 mins Read</span>
</div>
<mat-card-content class="p-24 b-b-1">
<div class="user-category">
<div>
<img src="{{ blogDetail()?.user }}" class="rounded-circle" width="40" />
</div>
<span class="f-s-12 m-y-16 f-w-600 rounded-pill p-x-8 p-y-4 d-inline-block text-dark bg-light">{{
blogDetail()?.category }}</span>
</div>
<mat-card-title class="f-s-36 lh-normal section-sub-title">{{
blogDetail()?.title }}
</mat-card-title>
<div class="d-flex align-items-center justify-content-center m-t-24 justify-content-between">
<div class="d-flex align-items-center gap-24">
<span class="f-s-14 d-flex align-items-center gap-8"><i-tabler name="eye" class="icon-18"></i-tabler>{{
blogDetail()?.views }}</span>
<span class="f-s-14 d-flex align-items-center gap-8"><i-tabler name="message-2"
class="icon-18"></i-tabler>4</span>
</div>
<span class="f-s-14 d-flex align-items-center">
<i-tabler name="point" class="icon-18"></i-tabler>
{{ blogDetail()?.date }}
</span>
</div>
</mat-card-content>
<mat-card-content class="heading-section">
<h2 class="f-s-28 lh-normal m-y-12 section-sub-title">Main Heading & Points</h2>
<p class="f-s-14">
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the
industry's standard dummy text ever since
the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It
has survived not only five centuries,
but also the leap into electronic typesetting,
remaining essentially unchanged. It was popularised in the
</p>
<ul>
<li class="f-s-14">Vivamus eu lacus scelerisque, placerat commodo lectus.</li>
<li class="f-s-14">Etiam et ante at ex porta fringilla.</li>
<li class="f-s-14">Nullam dignissim sem eu magna aliquet, sit amet volutpat tellus</li>
</ul>
<p class="f-s-14">
Unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not
only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was
popularised in the
</p>
<mat-divider></mat-divider>
<p class="f-s-14">
We are a dedicated team of passionate product managers, developers, UX/UI designers, QA engineers experts
helping businesses from new startups
</p>
<mat-divider></mat-divider>
<p class="f-s-14">
There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in
some form, by injected humour, or randomised words which don't look even slightly believable making this the
first true generator on the Internet. It uses a dictionary
</p>
<mat-divider class="m-b-16"></mat-divider>
<h2 class="f-s-21 lh-normal">Tags</h2>
<ul>
<li class="f-s-14">Trends</li>
<li class="f-s-14">Design</li>
<li class="f-s-14">Research</li>
</ul>
<mat-divider class="m-b-16"></mat-divider>
<h2 class="f-s-21 lh-normal">Share</h2>
<ul class="text-primary">
<li class="f-s-14"><a class="text-primary text-decoration-none" href="javascript:void(0)">Facebook</a></li>
<li class="f-s-14"><a class="text-primary text-decoration-none" href="javascript:void(0)">Twitter</a></li>
<li class="f-s-14"><a class="text-primary text-decoration-none" href="javascript:void(0)">Linkedin</a></li>
</ul>
<mat-divider class="m-b-16"></mat-divider>
<h2 class="f-s-21 lh-normal">Join our newsletter</h2>
<p class="f-s-14">Email address : <a href="javascript:void(0)" class="f-s-14 text-primary text-decoration-none">Subscribe</a></p>
</mat-card-content>
</mat-card>
}
<!-- ----------------------------------------------------------------- -->
<!-- If Blog isn't available -->
<!-- ----------------------------------------------------------------- -->
@if (!blogDetail() || blogDetail().length === 0) {
<mat-card class="cardWithShadow">
<mat-card-content>
<p>No blog post available.</p>
</mat-card-content>
</mat-card>
}
</div>
</div>
<div class="footer">
<app-footer></app-footer>
</div>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { BlogDetailsComponent } from './blog-details.component';
describe('BlogDetailsComponent', () => {
let component: BlogDetailsComponent;
let fixture: ComponentFixture<BlogDetailsComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [BlogDetailsComponent]
})
.compileComponents();
fixture = TestBed.createComponent(BlogDetailsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,40 @@
import { CommonModule } from '@angular/common';
import { Component, inject, OnInit, signal } from '@angular/core';
import { IconModule } from 'src/app/icon/icon.module';
import { MaterialModule } from 'src/app/material.module';
import { FooterComponent } from '../footer/footer.component';
import { FrontEndService } from 'src/app/services/apps/front-pages/front-end.service';
@Component({
selector: 'app-blog-details',
imports: [IconModule, MaterialModule, CommonModule,
FooterComponent
],
templateUrl: './blog-details.component.html',
styleUrl: './blog-details.component.scss'
})
export class BlogDetailsComponent implements OnInit {
blogDetail = signal<any>(null);
private frontendService = inject(FrontEndService);
ngOnInit(): void {
const selected = this.frontendService.getBlog()();
if (selected) {
this.blogDetail.set(selected);
} else {
// Fallback if accessed directly (e.g., from sidebar or refresh)
const defaultBlog = {
id: 1,
time: "2 mins Read",
imgSrc: "/assets/images/blog/blog-img1.jpg",
user: "/assets/images/profile/user-1.jpg",
title: "As yen tumbles, gadget-loving Japan goes for secondhand iPhones",
views: "9,125",
category: "Social",
comments: 3,
date: "Mon, Dec 23"
};
this.blogDetail.set(defaultBlog);
}
}
}

View File

@@ -0,0 +1,55 @@
<div class="banner-section bg-light-primary spacing-top-bottom">
<div class="container">
<p class="text-primary text-center text-uppercase f-s-14 m-t-0">
Blog Page
</p>
<h1 class="text-center f-s-48 section-sub-title lh-normal">Latest blog & news</h1>
</div>
</div>
<div class="spacing-top-bottom">
<div class="container">
<div class="row">
@for(cardimg of cardimgs; track cardimg.imgSrc) {
<div class="col-sm-6 col-lg-4">
<mat-card class="cardWithShadow card2 position-relative card-hover cursor-pointer" (click)="getNavigate(cardimg)">
<img mat-card-image src="{{ cardimg.imgSrc }}" alt="Photo of a Shiba Inu" />
<div class="card-overlay h-100 d-flex align-items-end justify-content-end">
<mat-chip class="m-r-16 bg-white">{{
cardimg.time
}}</mat-chip>
</div>
<mat-card-content class="p-y-24">
<div class="user-category">
<div>
<img src="{{ cardimg.user }}" class="rounded-circle" width="40" />
</div>
<mat-chip class="m-y-16 bg-light">{{
cardimg.category
}}</mat-chip>
</div>
<mat-card-title>{{ cardimg.title }}</mat-card-title>
<div class="d-flex align-items-center justify-content-center m-t-24">
<div class="d-flex align-items-center">
<span class="m-r-12 f-s-14 d-flex align-items-center"><i-tabler name="eye"
class="icon-18 m-r-4"></i-tabler>{{ cardimg.views }}</span>
<span class="f-s-14 d-flex align-items-center"><i-tabler name="message-2"
class="icon-18 m-r-4"></i-tabler>{{ cardimg.comments }}</span>
</div>
<span class="m-l-auto f-s-14 d-flex align-items-center">
<i-tabler name="point" class="icon-14 m-r-4 d-flex"></i-tabler>
{{ cardimg.date }}
</span>
</div>
</mat-card-content>
</mat-card>
</div>
}
</div>
</div>
</div>
<div class="footer">
<app-footer></app-footer>
</div>

View File

@@ -0,0 +1,24 @@
.social-btns {
margin-top: 20px;
.btn-icon {
width: 25px !important;
height: 25px !important;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
tabler-icon {
width: 16px !important;
height: 16px !important;
}
}
.btn-add-story {
font-size: 0.75rem;
padding: 0.35rem 0.75rem;
}
}

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { BlogComponent } from './blog.component';
describe('BlogComponent', () => {
let component: BlogComponent;
let fixture: ComponentFixture<BlogComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [BlogComponent]
})
.compileComponents();
fixture = TestBed.createComponent(BlogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,32 @@
import { Component, inject, OnInit } from '@angular/core';
import { IconModule } from 'src/app/icon/icon.module';
import { MaterialModule } from 'src/app/material.module';
import { cardimgs } from '../front-pagesData';
import { FooterComponent } from '../footer/footer.component';
import { Router } from '@angular/router';
import { FrontEndService } from 'src/app/services/apps/front-pages/front-end.service';
@Component({
selector: 'app-blog',
imports: [IconModule, MaterialModule, FooterComponent,],
templateUrl: './blog.component.html',
styleUrl: './blog.component.scss'
})
export class BlogComponent implements OnInit {
private router = inject(Router);
private frontendService = inject(FrontEndService);
cardimgs = cardimgs;
ngOnInit() {
console.log(cardimgs, 'cardimgs');
}
getNavigate(cardimg: any) {
console.log('cardimg--->', cardimg);
this.frontendService.setBlog(cardimg);
this.router.navigate(['front-pages/blog-details'])
}
}

View File

@@ -0,0 +1,103 @@
<div class="contact-content">
<!-- Light Blue Section -->
<div class="banner-section bg-light-primary p-y-80">
<div class="container m-b-80 p-b-80">
<div class="container-content">
<p class="text-primary text-center text-uppercase f-s-14 m-t-0"> Contact us</p>
<h1 class="text-center f-s-48 section-sub-title lh-normal">We'd love to hear from you</h1>
</div>
</div>
</div>
<div class="form-content">
<form>
<div class="container">
<!-- Map stays inside, but will visually float out -->
<div class="map-container overflow-hidden rounded">
<iframe class="overflow-hidden rounded"
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d6335071.017601874!2d7.472741070779207!3d34.000243243063756!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x126c2c82aeb63e77%3A0xb5b3d1a2f1304c8e!2sTunisia!5e0!3m2!1sen!2stn!4v1715499362503!5m2!1sen!2stn"
width="100%" height="400" style="border: 0" allowfullscreen="" loading="lazy"
referrerpolicy="no-referrer-when-downgrade"></iframe>
</div>
<div class="spacing-top-bottom">
<div class="row">
<div class="col-md-8 m-b-30">
<div class="row ">
<div class="col-md-6">
<!-- input -->
<mat-label class="f-s-14 f-w-600 m-b-8 d-block">First Name<span>*</span></mat-label>
<mat-form-field appearance="outline" class="w-100" color="primary">
<input matInput type="text" placeholder="First Name" />
</mat-form-field>
<!-- input -->
<mat-label class="f-s-14 f-w-600 m-b-8 d-block">Phone Number<span>*</span></mat-label>
<mat-form-field appearance="outline" class="w-100" color="primary">
<input matInput type="tel" placeholder="xxx xxx xxxx" />
</mat-form-field>
</div>
<div class="col-md-6">
<!-- input -->
<mat-label class="f-s-14 f-w-600 m-b-8 d-block">Last Name<span>*</span></mat-label>
<mat-form-field appearance="outline" class="w-100" color="primary">
<input matInput type="text" placeholder="Last Name" />
</mat-form-field>
<!-- input -->
<mat-label class="f-s-14 f-w-600 m-b-8 d-block">Email<span>*</span></mat-label>
<mat-form-field appearance="outline" class="w-100" color="primary">
<input matInput type="mail" placeholder="Email address" />
</mat-form-field>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<mat-label class="f-s-14 f-w-600 m-b-8 d-block">Enquire related to<span>*</span>
</mat-label>
<mat-form-field appearance="outline" class="w-100">
<mat-select value="General Enquiry">
<mat-option value="General Enquiry">General Enquiry</mat-option>
<mat-option value="General Enquiry 2">General Enquiry 2</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<mat-label class="f-s-14 f-w-600 m-b-8 d-block">Message</mat-label>
<mat-form-field appearance="outline" class="w-100" color="primary">
<textarea matInput rows="5" placeholder="Write your message here"></textarea>
</mat-form-field>
</div>
</div>
<button mat-flat-button>Submit</button>
</div>
<div class="col-md-4 right-side-content">
<mat-card class="shadow-none bg-primary rounded-8 p-8">
<mat-card-content>
<div>
<h6 class="f-s-20 m-b-16 text-white">Reach Out Today</h6>
<p class="f-s-14 m-0 text-white">
Have questions or need assistance? We're just a message
away.
</p>
</div>
<mat-divider class="m-y-30"></mat-divider>
<div>
<h6 class="f-s-20 m-b-16 text-white">Our Location</h6>
<p class="f-s-14 m-0 text-white">
Visit us in person or find our contact details to connect
with us directly.
</p>
</div>
</mat-card-content>
</mat-card>
</div>
</div>
</div>
</div>
</form>
</div>
<div class="footer">
<app-footer></app-footer>
</div>
</div>

View File

@@ -0,0 +1,3 @@
.map-container{
margin-top: -200px;
}

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ContactComponent } from './contact.component';
describe('ContactComponent', () => {
let component: ContactComponent;
let fixture: ComponentFixture<ContactComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ContactComponent]
})
.compileComponents();
fixture = TestBed.createComponent(ContactComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,14 @@
import { Component } from '@angular/core';
import { IconModule } from 'src/app/icon/icon.module';
import { MaterialModule } from 'src/app/material.module';
import { FooterComponent } from '../footer/footer.component';
@Component({
selector: 'app-contact',
imports: [MaterialModule,IconModule,FooterComponent],
templateUrl: './contact.component.html',
styleUrl: './contact.component.scss'
})
export class ContactComponent {
}

View File

@@ -0,0 +1,94 @@
<div class="footer-content">
<div class="custom-container footer-dashboard">
<div class="bg-light-primary rounded-8 footer-container m-b-80 overflow-hidden">
<div class="row">
<div class="col-lg-6">
<div class="spacing-top-bottom spacing-left left-side-content">
<h2 class="f-s-40 m-b-24 lh-normal section-sub-title">
Develop with feature-rich Angular Dashboard
</h2>
<div class="m-b-24 hstack">
<a href="authentication/login" target="_blank" mat-flat-button color="primary" class="">Member Login</a>
<a href="authentication/side-register" target="_blank" mat-stroked-button color="primary"
class="border-primary">Register as Member</a>
</div>
<span class="f-s-14 f-w-600"> One-time purchase</span> - no
recurring fees.
</div>
</div>
<div class="col-md-6 d-none d-lg-block">
<img src="assets/images/front-pages/design-collection.png" alt="bg-img" class="imgStyleDash" />
</div>
</div>
</div>
</div>
<div class="footer-wrapper">
<div class="container">
<div class="row">
<div class="col-md-3 col-6 m-b-30">
<div class="listContainer">
<h5 class="f-s-16 f-w-600 m-b-30">Applications</h5>
<mat-list role="list" class="p-y-0">
@for (item of applicationsItems; track item) {
<a class="text-decoration-none d-block m-b-20" [routerLink]="[item.href]">
{{ item.title }}
</a>
}
</mat-list>
</div>
</div>
<div class="col-md-3 col-6 m-b-30">
<div class="listContainer">
<h5 class="f-s-16 f-w-600 m-b-30">Forms</h5>
<mat-list role="list" class="p-y-0">
@for (item of formsItems; track item) {
<a class="text-decoration-none d-block m-b-20" [routerLink]="[item.href]">
{{ item.title }}
</a>
}
</mat-list>
</div>
</div>
<div class="col-md-3 col-6 m-b-30">
<div class="listContainer">
<h5 class="f-s-16 f-w-600 m-b-30">Tables</h5>
<mat-list role="list" class="p-y-0">
@for (item of tablesItems; track item) {
<a class="text-decoration-none d-block m-b-20" [routerLink]="[item.href]">
{{ item.title }}
</a>
}
</mat-list>
</div>
</div>
<div class="col-md-3 col-6 m-b-30">
<h5 class="f-s-16 f-w-600 m-b-30">Follow us</h5>
<div class="d-flex align-items-center gap-20">
@for (icon of socialIcons; track icon.src) {
<img [src]="icon.src" [matTooltip]="icon.tooltip" alt="social-icon" width="22" height="22"
class="cursor-pointer" />
}
</div>
</div>
</div>
<div class="d-flex align-items-center justify-content-between p-y-30 b-t-1 flex-wrap">
<!-- Left side -->
<div class="d-flex align-items-center gap-4">
<img src="assets/images/landingpage/favicon.png" alt="logo" width="20" height="15" />
<h6 class="f-s-16 f-w-500">All rights reserved by Modernize.</h6>
</div>
<!-- Right side -->
<div class="d-flex justify-content-end align-items-center">
<p class="f-s-16 m-0">
Designed & Developed by
<a href="https://adminmart.com/" target="_blank" class="text-decoration-none text-primary">
AdminMart </a>.
</p>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,13 @@
.footer-content{
.custom-container {
max-width: 1400px;
margin: 0 auto;
width: 100%;
padding: 0 15px;
}
}
.imgStyleDash {
position: absolute;
}

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FooterComponent } from './footer.component';
describe('FooterComponent', () => {
let component: FooterComponent;
let fixture: ComponentFixture<FooterComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [FooterComponent]
})
.compileComponents();
fixture = TestBed.createComponent(FooterComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,95 @@
import { Component } from '@angular/core';
import { IconModule } from 'src/app/icon/icon.module';
import { MaterialModule } from 'src/app/material.module';
import { RouterLink } from '@angular/router';
@Component({
selector: 'app-footer',
imports: [MaterialModule, IconModule, RouterLink],
templateUrl: './footer.component.html',
styleUrl: './footer.component.scss'
})
export class FooterComponent {
applicationsItems = [
{
title: 'Kanban',
href: "/apps/kanban"
},
{
title: 'Invoice List',
href: "/apps/invoice/list"
},
{
title: 'eCommerce',
href: "/apps/product/shop"
},
{
title: 'Chats',
href: "/apps/chat"
},
{
title: 'Tickets',
href: "/apps/tickets"
},
{
title: 'Blog',
href: "/apps/blog/post"
},
];
formsItems = [
{
title: 'Form Layout',
href: "/forms/form-layouts"
},
{
title: 'Form Horizontal',
href: "/forms/form-horizontal"
},
{
title: 'Form Wizard',
href: "/forms/form-wizard"
},
{
title: 'Form Vertical',
href: "/forms/form-vertical"
},
{
title: 'Form Toastr',
href: "/forms/form-toastr"
},
];
tablesItems = [
{
title: 'Basic Table',
href: "/tables/basic-table"
},
{
title: 'Multi Header Footer Table',
href: "/tables/multi-header-footer-table"
},
{
title: 'Pagination Table',
href: "/tables/pagination-table"
},
{
title: 'Dynamic Table',
href: "/tables/dynamic-table"
},
{
title: 'HTTP Table',
href: "/tables/http-table"
},
{
title: 'Sortable Table',
href: "/tables/sortable-table"
},
];
socialIcons = [
{ src: 'assets/images/front-pages/icon-facebook.svg', tooltip: 'Facebook' },
{ src: 'assets/images/front-pages/icon-twitter.svg', tooltip: 'Twitter' },
{ src: 'assets/images/front-pages/icon-instagram.svg', tooltip: 'Instagram' },
];
}

View File

@@ -0,0 +1,28 @@
import { Routes } from '@angular/router';
import { HomepageComponent } from './homepage/homepage.component';
import { AboutUsComponent } from './about-us/about-us.component';
import { HomepageDetailsComponent } from './homepage-details/homepage-details.component';
import { BlogComponent } from './blog/blog.component';
import { PortfolioComponent } from './portfolio/portfolio.component';
import { PricingComponent } from './pricing/pricing.component';
import { ContactComponent } from './contact/contact.component';
import { BlogDetailsComponent } from './blog-details/blog-details.component';
export const FrontPagesRoutes: Routes = [
{
path: '',
component: HomepageComponent, // acts as layout shell
children: [
{ path: '', redirectTo: 'homepage', pathMatch: 'full' },
{ path: 'homepage', component: HomepageDetailsComponent }, // real homepage content
{ path: 'about', component: AboutUsComponent },
{path:'blog',component:BlogComponent },
{ path: 'portfolio', component: PortfolioComponent },
{ path: 'pricing', component: PricingComponent },
{ path: 'contact', component: ContactComponent },
{ path: 'blog-details', component: BlogDetailsComponent },
],
},
];

View File

@@ -0,0 +1,768 @@
interface cardimgs {
id: number;
time: string;
imgSrc: string;
user: string;
title: string;
views: string;
category: string;
comments: number;
date: string;
}
interface productcards {
id: number;
imgSrc: string;
title: string;
price: string;
rprice: string;
date: string;
}
interface Framework {
src: string;
alt: string;
tooltip: string;
}
interface followercards {
id: number;
imgSrc: string;
title: string;
}
interface setupCards {
id: number;
img: string;
color: string;
title: string;
subtitle: string;
imgMain?:string;
}
export const cardimgs: cardimgs[] = [
{
id: 1,
time: '2 mins Read',
imgSrc: '/assets/images/blog/blog-img1.jpg',
user: '/assets/images/profile/user-1.jpg',
title: 'As yen tumbles, gadget-loving Japan goes for secondhand iPhones',
views: '9,125',
category: 'Social',
comments: 3,
date: 'Mon, Dec 23',
},
{
id: 2,
time: '3 mins Read',
imgSrc: '/assets/images/blog/blog-img2.jpg',
user: '/assets/images/profile/user-2.jpg',
title:
'Intel loses bid to revive antitrust case against patent foe Fortress',
views: '9,125',
category: 'Gadget',
comments: 3,
date: 'Sun, Dec 23',
},
{
id: 3,
time: '4 mins Read',
imgSrc: '/assets/images/blog/blog-img3.jpg',
user: '/assets/images/profile/user-3.jpg',
title: 'COVID outbreak deepens as more lockdowns loom in China',
views: '9,125',
category: 'Health',
comments: 12,
date: 'Sat, Dec 23',
},
{
id: 4,
time: '2 mins Read',
imgSrc: '/assets/images/blog/blog-img4.jpg',
user: '/assets/images/profile/user-1.jpg',
title: 'As yen tumbles, gadget-loving Japan goes for secondhand iPhones',
views: '9,125',
category: 'Social',
comments: 3,
date: 'Mon, Dec 23',
},
{
id: 5,
time: '3 mins Read',
imgSrc: '/assets/images/blog/blog-img5.jpg',
user: '/assets/images/profile/user-2.jpg',
title:
'Intel loses bid to revive antitrust case against patent foe Fortress',
views: '9,125',
category: 'Gadget',
comments: 3,
date: 'Sun, Dec 23',
},
{
id: 6,
time: '4 mins Read',
imgSrc: '/assets/images/blog/blog-img6.jpg',
user: '/assets/images/profile/user-3.jpg',
title: 'COVID outbreak deepens as more lockdowns loom in China',
views: '9,125',
category: 'Health',
comments: 12,
date: 'Sat, Dec 23',
},
{
id: 7,
time: '2 mins Read',
imgSrc: '/assets/images/blog/blog-img10.jpg',
user: '/assets/images/profile/user-1.jpg',
title: 'As yen tumbles, gadget-loving Japan goes for secondhand iPhones',
views: '9,125',
category: 'Social',
comments: 3,
date: 'Mon, Dec 23',
},
{
id: 8,
time: '3 mins Read',
imgSrc: '/assets/images/blog/blog-img8.jpg',
user: '/assets/images/profile/user-2.jpg',
title:
'Intel loses bid to revive antitrust case against patent foe Fortress',
views: '9,125',
category: 'Gadget',
comments: 3,
date: 'Sun, Dec 23',
},
{
id: 9,
time: '4 mins Read',
imgSrc: '/assets/images/blog/blog-img9.jpg',
user: '/assets/images/profile/user-3.jpg',
title: 'COVID outbreak deepens as more lockdowns loom in China',
views: '9,125',
category: 'Health',
comments: 12,
date: 'Sat, Dec 23',
},
];
export const productcards: productcards[] = [
{
id: 1,
imgSrc: 'assets/images/products/s4.jpg',
title: 'Boat Headphone',
price: '285',
rprice: '375',
date: 'Tue, Apr 03, 2025',
},
{
id: 2,
imgSrc: 'assets/images/products/s5.jpg',
title: 'MacBook Air Pro',
price: '285',
rprice: '375',
date: 'Tue, Apr 10, 2025',
},
{
id: 3,
imgSrc: 'assets/images/products/s7.jpg',
title: 'Red Velvet Dress',
price: '285',
rprice: '375',
date: 'Tue, Apr 15, 2025',
},
{
id: 4,
imgSrc: 'assets/images/products/s11.jpg',
title: 'Soft Plush Teddy',
price: '285',
rprice: '375',
date: 'Tue, Apr 12, 2025',
},
{
id: 5,
imgSrc: 'assets/images/products/s2.jpg',
title: 'Boat Bass Booster',
price: '285',
rprice: '375',
date: 'Tue, Apr 14, 2025',
},
{
id: 6,
imgSrc: 'assets/images/products/s6.jpg',
title: 'MacBook Ultra Slim',
price: '285',
rprice: '375',
date: 'Tue, Apr 18, 2025',
},
{
id: 7,
imgSrc: 'assets/images/products/s8.jpg',
title: 'Crimson Party Dress',
price: '285',
rprice: '375',
date: 'Tue, Apr 20, 2025',
},
{
id: 8,
imgSrc: 'assets/images/products/s12.jpg',
title: 'Cuddly Teddy Gift',
price: '285',
rprice: '375',
date: 'Tue, Apr 22, 2025',
},
{
id: 9,
imgSrc: 'assets/images/products/s4.jpg',
title: 'Boat Sonic Headset',
price: '285',
rprice: '375',
date: 'Tue, Apr 25, 2025',
},
{
id: 10,
imgSrc: 'assets/images/products/s5.jpg',
title: 'MacBook Pro 2025',
price: '285',
rprice: '375',
date: 'Tue, Apr 27, 2025',
},
{
id: 11,
imgSrc: 'assets/images/products/s7.jpg',
title: 'Evening Gown - Red',
price: '285',
rprice: '375',
date: 'Tue, Apr 29, 2025',
},
{
id: 12,
imgSrc: 'assets/images/products/s11.jpg',
title: 'Fluffy Bear Surprise',
price: '285',
rprice: '375',
date: 'Tue, Apr 30, 2025',
},
];
export const frameworks: Framework[] = [
{
src: 'assets/images/landingpage/frameworks/angular.svg',
alt: 'Angular',
tooltip: 'Angular',
},
{
src: 'assets/images/landingpage/frameworks/material.svg',
alt: 'Angular Material',
tooltip: 'Angular Material',
},
{
src: 'assets/images/landingpage/frameworks/logo-ts.svg',
alt: 'Typescript',
tooltip: 'Typescript',
},
{
src: 'assets/images/landingpage/frameworks/icon-tabler.svg',
alt: 'Tabler Icon',
tooltip: 'Tabler Icon',
},
];
export const tiles = [
{
id: 1,
text: 'Light & Dark Color Schemes',
cols: 1,
rows: 1,
color: '#FFF6E5',
icon: 'svgs/icon-briefcase.svg',
subtitle: 'Choose your preferred visual style effortlessly.',
},
{
id: 2,
text: 'New Demos',
cols: 2,
rows: 2,
color: '#E9F1FF',
icon: 'logos/logoIcon.svg',
img: 'landingpage/background/screen1.png',
subtitle:
'Brand new demos to help you build the perfect dashboard:<br><strong>Dark and Right-to-Left.</strong>',
},
{
id: 3,
text: 'Code Improvements',
cols: 1,
rows: 1,
color: '#E7FFF2',
icon: 'logos/icon-speech-bubble.svg',
subtitle: 'Benefit from continuous improvements and optimizations.',
},
{
id: 4,
text: '12+ Ready to Use Application Designs',
cols: 1,
rows: 1,
color: '#E4F4FF',
icon: 'icon-layer.svg',
img: 'landingpage/background/feature-apps.png',
subtitle: 'Instantly deployable designs for your applications.',
},
{
id: 5,
text: '50+ UI Components',
cols: 1,
rows: 1,
color: '#FFECEC',
icon: 'logos/icon-favorites.svg',
subtitle: 'A rich collection for seamless user experiences.',
},
];
export const users = [
{ name: 'Jenny Wilson', img: '/assets/images/profile/user-1.jpg' },
{ name: 'Robert Fox', img: '/assets/images/profile/user-2.jpg' },
{ name: 'Kristin Watson', img: '/assets/images/profile/user-3.jpg' },
{ name: 'Darlene Robertson', img: '/assets/images/profile/user-4.jpg' },
{ name: 'Jacob Jones', img: '/assets/images/profile/user-5.jpg' },
];
export const plans = [
{
title: 'Single Use',
description:
'Use for single end product which end users cant be charged for.',
price: 49,
period: 'one time pay',
features: [
{ text: 'Full source code', included: true },
{ text: 'Documentation', included: true },
{ text: 'Use in SaaS app', included: false },
{ text: 'One Project', included: true, bold: true },
{ text: 'One Year Technical Support', included: true },
{ text: 'One Year Free Updates', included: true },
],
},
{
title: 'Multiple Use',
description:
'Use for unlimited end products end users cant be charged for.',
price: 89,
period: 'one time pay',
features: [
{ text: 'Full source code', included: true },
{ text: 'Documentation', included: true },
{ text: 'Use in SaaS app', included: false },
{ text: 'Unlimited Project', included: true, bold: true },
{ text: 'One Year Technical Support', included: true },
{ text: 'One Year Free Updates', included: true },
],
},
{
title: 'Extended Use',
description:
'Use for single end product which end users can be charged for.',
price: 299,
period: 'one time pay',
popular: true,
features: [
{ text: 'Full source code', included: true },
{ text: 'Documentation', included: true },
{ text: 'Use in SaaS app', included: true },
{ text: 'One Project', included: true, bold: true },
{ text: 'One Year Technical Support', included: true },
{ text: 'One Year Free Updates', included: true },
],
},
{
title: 'Unlimited Use',
description:
'Use in unlimited end products end users can be charged for.',
price: 499,
period: 'one time pay',
features: [
{ text: 'Full source code', included: true },
{ text: 'Documentation', included: true },
{ text: 'Use in SaaS app', included: true },
{ text: 'Unlimited Project', included: true, bold: true },
{ text: 'One Year Technical Support', included: true },
{ text: 'One Year Free Updates', included: true },
],
},
];
export const paymentLogos = [
{ src: 'assets/images/front-pages/icon-visa.svg', alt: 'visa', tooltip: 'Visa' },
{
src: 'assets/images/front-pages/icon-mastercard.svg',
alt: 'mastercard',
tooltip: 'Master Card',
},
{
src: 'assets/images/front-pages/icon-american-express.svg',
alt: 'american express',
tooltip: 'American Express',
},
{
src: 'assets/images/front-pages/icon-discover.svg',
alt: 'discover',
tooltip: 'Discover',
},
{
src: 'assets/images/front-pages/icon-paypal.svg',
alt: 'paypal',
tooltip: 'Paypal',
},
{
src: 'assets/images/front-pages/icon-masetro.svg',
alt: 'maestro',
tooltip: 'Maestro',
},
{ src: 'assets/images/front-pages/icon-jcb.svg', alt: 'jcb', tooltip: 'JCB' },
{
src: 'assets/images/front-pages/icon-diners.svg',
alt: 'diners',
tooltip: 'Diners',
},
];
export const faqList = [
{
question: 'What is included with my purchase?',
answer:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget.',
},
{
question: 'Are there any recurring fees?',
answer:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget.',
},
{
question: 'Can i use template on multiple projects? ',
answer:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget.',
},
{
question:
'Can i use customize the admin dashboard template to match my brand?',
answer:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget.',
},
{
question: 'Are any restrictions on using the template?',
answer:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget.',
},
{
question: 'How can i get support after purchase? ',
answer:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse malesuada lacus ex, sit amet blandit leo lobortis eget.',
},
];
export const followercardsFirst: followercards[] = [
{
id: 1,
imgSrc: '/assets/images/front-pages/icon-color.svg',
title: '6 Themes Colors',
},
{
id: 2,
imgSrc: '/assets/images/front-pages/icon-sidebar.svg',
title: 'Dard & Light Sidebar',
},
{
id: 3,
imgSrc: '/assets/images/front-pages/icon-components.svg',
title: '50+ UI Components',
},
{
id: 4,
imgSrc: '/assets/images/front-pages/icon-pages.svg',
title: '65+ pages Templates',
},
{
id: 5,
imgSrc: '/assets/images/front-pages/icon-color.svg',
title: '6 Themes Colors',
},
{
id: 6,
imgSrc: '/assets/images/front-pages/icon-sidebar.svg',
title: 'Dard & Light Sidebar',
},
{
id: 7,
imgSrc: '/assets/images/front-pages/icon-components.svg',
title: '50+ UI Components',
},
{
id: 8,
imgSrc: '/assets/images/front-pages/icon-pages.svg',
title: '65+ pages Templates',
},
{
id: 9,
imgSrc: '/assets/images/front-pages/icon-color.svg',
title: '6 Themes Colors',
},
{
id: 10,
imgSrc: '/assets/images/front-pages/icon-sidebar.svg',
title: 'Dard & Light Sidebar',
},
{
id: 11,
imgSrc: '/assets/images/front-pages/icon-components.svg',
title: '50+ UI Components',
},
{
id: 12,
imgSrc: '/assets/images/front-pages/icon-pages.svg',
title: '65+ pages Templates',
},
];
export const followercardSecond: followercards[] = [
{
id: 1,
imgSrc: '/assets/images/front-pages/icon-framework.svg',
title: 'Material UI',
},
{
id: 2,
imgSrc: '/assets/images/front-pages/icon-icons.svg',
title: '3400+ icons',
},
{
id: 3,
imgSrc: '/assets/images/front-pages/icon-responsive.svg',
title: 'Fully responsive',
},
{
id: 4,
imgSrc: '/assets/images/front-pages/icon-sass.svg',
title: 'Sassbase css',
},
{
id: 5,
imgSrc: '/assets/images/front-pages/icon-framework.svg',
title: 'Material UI',
},
{
id: 6,
imgSrc: '/assets/images/front-pages/icon-icons.svg',
title: '3400+ icons',
},
{
id: 7,
imgSrc: '/assets/images/front-pages/icon-responsive.svg',
title: 'Fully responsive',
},
{
id: 8,
imgSrc: '/assets/images/front-pages/icon-sass.svg',
title: 'Sassbase css',
},
{
id: 9,
imgSrc: '/assets/images/front-pages/icon-framework.svg',
title: 'Material UI',
},
{
id: 10,
imgSrc: '/assets/images/front-pages/icon-icons.svg',
title: '3400+ icons',
},
{
id: 11,
imgSrc: '/assets/images/front-pages/icon-responsive.svg',
title: 'Fully responsive',
},
{
id: 12,
imgSrc: '/assets/images/front-pages/icon-sass.svg',
title: 'Sassbase css',
},
];
export const followercardThird: followercards[] = [
{
id: 1,
imgSrc: '/assets/images/front-pages/icon-customize.svg',
title: 'Easy to Customize',
},
{
id: 2,
imgSrc: '/assets/images/front-pages/icon-chart.svg',
title: 'Lots of Chart Options',
},
{
id: 3,
imgSrc: '/assets/images/front-pages/icon-table.svg',
title: 'Lots of Table Examples',
},
{
id: 4,
imgSrc: '/assets/images/front-pages/icon-update.svg',
title: 'Regular Updates',
},
{
id: 5,
imgSrc: '/assets/images/front-pages/icon-support.svg',
title: 'Dedicated Support',
},
{
id: 6,
imgSrc: '/assets/images/front-pages/icon-framework.svg',
title: 'Easy to Customize',
},
{
id: 7,
imgSrc: '/assets/images/front-pages/icon-icons.svg',
title: 'Lots of Chart Options',
},
{
id: 8,
imgSrc: '/assets/images/front-pages/icon-responsive.svg',
title: 'Lots of Table Examples',
},
{
id: 9,
imgSrc: '/assets/images/front-pages/icon-sass.svg',
title: 'Regular Updates',
},
{
id: 10,
imgSrc: '/assets/images/front-pages/icon-framework.svg',
title: 'Dedicated Support',
},
{
id: 11,
imgSrc: '/assets/images/front-pages/icon-framework.svg',
title: 'Easy to Customize',
},
{
id: 12,
imgSrc: '/assets/images/front-pages/icon-icons.svg',
title: 'Lots of Chart Options',
},
];
export const topcardsGrid = [
{ title: 'Light & Dark Color Schemes', subtitle: 'Choose your preferred visual style effortlessly.',
img: '/assets/images/svgs/icon-briefcase.svg', color: 'warning' },
{ title: '12+ Ready to Use Application Designs', subtitle: 'Instantly deployable designs for your applications.',
img: 'assets/icons/icon2.png', color: 'secondary',imgMain: '/assets/images/landingpage/background/feature-apps.png', },
{ title: 'New Demos', subtitle: 'Brand new demos to help you build the perfect dashboard: <strong>Dark and Right-to-Left.</strong>',
img: '/assets/images/front-pages/logoIcon.svg', color: 'primary',imgMain: '/assets/images/landingpage/background/screen1.png' },
{ title: 'Code Improvements', subtitle: 'Benefit from continuous improvements and optimizations.',
img: '/assets/images/front-pages/icon-speech-bubble.svg', color: 'success' },
{ title: '50+ UI Components', subtitle: 'A rich collection for seamless user experiences.',
img: '/assets/images/front-pages/icon-favorites.svg', color: 'error' },
];
export const setupCards:setupCards[] = [
{
id: 1,
color: 'warning',
img: '/assets/images/svgs/icon-briefcase.svg',
title: 'Light & Dark Color Schemes',
subtitle: 'Choose your preferred visual style effortlessly.',
},
{
id: 2,
color: 'secondary',
img: '/assets/images/svgs/icon-connect.svg',
title: '12+ Ready to Use Application Designs',
subtitle: 'Instantly deployable designs for your applications.',
imgMain: '/assets/images/landingpage/background/feature-apps.png'
},
{
id: 3,
color: 'success',
img: '/assets/images/svgs/icon-speech-bubble.svg',
title: 'Code Improvements',
subtitle: 'Benefit from continuous improvements and optimizations.',
},
{
id: 4,
color: 'error',
img: '/assets/images/svgs/icon-favorites.svg',
title: '50+ UI Components',
subtitle: 'A rich collection for seamless user experiences.',
},
];
export const stats = [
{
label: 'Founded',
value: '2019',
description: 'When we founded Modernize',
},
{
label: 'Growth',
value: '1,400%',
description: 'Revenue growth in 2024',
},
{
label: 'Customers',
value: '300k+',
description: 'Customers on Modernize',
},
{
label: 'Dashboards',
value: '25k+',
description: 'Dashboards built using Modernize',
},
];
export const team = [
{id: 1,
name: 'Alex Martinez',
position: 'CEO & Co-Founder',
image: 'assets/images/front-pages/user1.jpg'
},
{
id: 2,
name: 'Jordan Nguyen',
position: 'CTO & Co-Founder',
image: 'assets/images/front-pages/user2.jpg'
},
{
id: 3,
name: 'Taylor Roberts',
position: 'Product Manager',
image: 'assets/images/front-pages/user3.jpg'
},
{id: 4,
name: 'Morgan Patel',
position: 'Lead Developer',
image: 'assets/images/front-pages/user4.jpg'
},
{
id: 5,
name: 'Andrew Grant',
position: 'Product Manager',
image: 'assets/images/front-pages/user5.jpg'
},
{
id: 6,
name: 'Leo Pratt',
position: 'Lead Developer',
image: 'assets/images/front-pages/user3.jpg'
},
{
id: 7,
name: 'C. A. Nunez',
position: 'CEO & Co-Founder',
image: 'assets/images/front-pages/user2.jpg'
},
{
id: 8,
name: 'Leo Maxwell',
position: 'Lead Developer',
image: 'assets/images/front-pages/user1.jpg'
}
];

View File

@@ -0,0 +1,603 @@
<div class="home-page">
<div class="bg-light-primary home-page-header">
<div class="header-container-content custom-container m-x-auto">
<div class="row justify-content-center">
<div class="col-md-8">
<h1 class="banner-title text-center m-t-48">
Most powerful &
<span class="text-primary">developer friendly </span>
dashboard
</h1>
</div>
</div>
<div class="row align-items-end justify-content-center">
@if(!isMobileView){
<div class="col-md-3 d-none d-lg-block cardPosition">
<img src="assets/images/front-pages/banner-top-left.svg" alt="banner-top-left"
class="img-fluid rounded-8 float-image w-100" />
</div>
}
<div class="col-md-6 m-b-10">
<div class="row m-t-24">
<div class="col-12 d-flex gap-20 align-items-center justify-content-center chipContainer">
<div class="social-chips flex-shrink-0">
<img src="assets/images/profile/user-2.jpg" width="40" alt="social" class="rounded-circle" />
<img src="assets/images/profile/user-3.jpg" width="40" alt="social" class="rounded-circle" />
<img src="assets/images/profile/user-4.jpg" width="40" alt="social" class="rounded-circle" />
</div>
<div class="f-s-16 f-w-500">
52,589+ developers & agencies using our templates
</div>
</div>
</div>
<div class="d-flex align-items-center justify-content-center m-t-24 gap-20 loginBtn">
<a mat-flat-button color="primary" [routerLink]="'/authentication/login'"><span
class="p-y-10">Login</span></a>
<div class="d-flex align-items-center" matRipple [matRippleCentered]="centered"
[matRippleDisabled]="disabled" [matRippleUnbounded]="unbounded" [matRippleRadius]="radius"
[matRippleColor]="color" [ngClass]="{
'rounded bg-light-primary': showBackground,
'p-y-2': true,
'p-x-7': true
}" (click)="openDialog(true)">
<button mat-mini-fab class="text-primary play-button m-l-10"
aria-label="Example icon button with a delete icon">
<i-tabler class="icon-18 d-flex margin-auto" name="player-play"></i-tabler></button><span
class="textSee f-s-14 f-w-500 m-x-10">
See how it works</span>
</div>
</div>
<div class="d-flex align-items-center gap-20 justify-content-center framework m-t-32">
@for (framework of frameworks; track framework.tooltip) {
<a href="javascript:void(0)"
class="rounded-8 m-b-0 bg-white icon-54 d-flex align-items-center justify-content-center"
matTooltip="{{ framework.tooltip }}" matTooltipPosition="below">
<img [src]="framework.src" [alt]="framework.alt" class="" width="28" height="28" />
</a>
}
</div>
</div>
@if(!isMobileView){
<div class="col-md-3 d-none d-lg-block cardPositionTwo">
<img src="assets/images/front-pages/banner-top-right.svg" alt="banner-top-right"
class="img-fluid rounded-8 float-image w-100" />
</div>
}
</div>
@if (!isMobileView) {
<div class="row d-none d-lg-block m-t-30">
<div class="col-12">
<img src="assets/images/front-pages/bottom-part.svg" alt="bottom-part" class="w-100 img-fluid d-block" />
</div>
</div>
}
</div>
</div>
<div class="introducing-section dashboardCards spacing-top-bottom">
<div class="container card-container">
<div class="row justify-content-center">
<div class="col-md-6">
<p class="text-center m-t-0">
Introducing Modernize's Light & Dark Skins, Exceptional Dashboards,
and Dynamic Pages - Stay Updated on What's New!
</p>
</div>
</div>
<!--new-->
<!-- DESKTOP VIEW -->
@if (!isMobileView) {
<div class="row m-t-24">
<!-- Column 1: Light & Dark + 12+ Designs -->
<div class="col-md-4">
<div>
@for (topcard of topcards; track topcard.title) {
@if (topcard.title === 'Light & Dark Color Schemes' || topcard.title.includes('12+')) {
<mat-card class="shadow-none text-center rounded-12 bg-light-{{ topcard.color }} card-box p-x-30 p-y-44">
<mat-card-content>
@if (topcard.title === 'Light & Dark Color Schemes') {
<img [src]="topcard.img" alt="icon" width="40" />
}
<h6 class="f-s-16 m-t-16">{{ topcard.title }}</h6>
<p class="f-s-14 m-t-16">{{ topcard.subtitle }}</p>
@if (topcard.title.includes('12+')) {
<img [src]="topcard.imgMain" alt="image" class="img-fluid w-100 m-t-16 m-b--48" />
}
</mat-card-content>
</mat-card>
}
}
</div>
</div>
<div class="col-md-4">
<div>
@for (topcard of topcards; track topcard.title)
{
@if
(topcard.title.includes('New Demos')) {
<mat-card class="shadow-none text-center rounded-12 bg-light-{{
topcard.color
}} card-box tall-card p-x-30 p-y-48">
<mat-card-content>
<img [src]="topcard.img" alt="icon" width="40" class="" />
<h2 class="f-s-40 m-t-48 lh-lg section-sub-title">{{ topcard.title }}</h2>
<p class="f-s-14 m-t-20 m-b-0" [innerHTML]="topcard.subtitle"></p>
<img src="assets/images/landingpage/background/screen1.png" alt="demo" class="img-fluid w-100 m-t-48" />
</mat-card-content>
</mat-card>
} }
</div>
</div>
<!-- Column 2: Code Improvements + UI Components -->
<div class="col-md-4">
<div>
@for (topcard of topcards; track topcard.title) {
@if (topcard.title.includes('Code Improvements') || topcard.title.includes('UI Components')) {
<mat-card class="shadow-none text-center rounded-12 bg-light-{{ topcard.color }} card-box p-x-30 p-y-48">
<mat-card-content>
<img [src]="topcard.img" alt="icon" width="40" />
<h6 class="f-s-16 m-t-16">{{ topcard.title }}</h6>
<p class="f-s-14 m-t-16">{{ topcard.subtitle }}</p>
</mat-card-content>
</mat-card>
}
}
</div>
</div>
</div>
}
<!-- MOBILE VIEW -->
@else {
<div class="grid-container m-t-24 m-x-0">
@for (topcard of topcards; track topcard.title) {
@if (!topcard.title.includes('New Demos')) {
<mat-card class="shadow-none text-center rounded-12 bg-light-{{ topcard.color }} card-box p-x-24 p-y-32">
<mat-card-content>
@if (!topcard.title.includes('12+')) {
<img [src]="topcard.img" alt="icon" width="40" />
}
<h6 class="f-s-16 m-t-16">{{ topcard.title }}</h6>
<p class="f-s-14 m-t-16">{{ topcard.subtitle }}</p>
@if (topcard.title.includes('12+')) {
<img [src]="topcard.imgMain" alt="image" class="img-fluid w-100 m-t-16" />
}
</mat-card-content>
</mat-card>
}
}
</div>
<div>
@for (topcard of topcards; track topcard.title)
{
@if
(topcard.title.includes('New Demos')) {
<mat-card class="shadow-none text-center rounded-12 bg-light-{{
topcard.color
}} card-box tall-card p-x-32 p-y-48">
<mat-card-content>
<img [src]="topcard.img" alt="icon" width="40" class="" />
<h6 class="f-s-40 m-t-32 tall-card-title section-sub-title">{{ topcard.title }}</h6>
<p class="f-s-14 m-t-20" [innerHTML]="topcard.subtitle"></p>
<img src="assets/images/landingpage/background/screen1.png" alt="demo" class="img-fluid w-100 m-t-30" />
</mat-card-content>
</mat-card>
} }
</div>
}
<!--end-->
</div>
</div>
<div class="tab-header">
<mat-divider></mat-divider>
<div class="container">
<mat-tab-group headerPosition="below" [(selectedIndex)]="selectedIndex" class="profileTabs">
<mat-tab>
<ng-template mat-tab-label>
<tabler-icon name="user-circle" class="m-r-10 icon-24"></tabler-icon>
<span class="tab-label f-s-18 f-w-500">Team Scheduling</span>
</ng-template>
</mat-tab>
<mat-tab>
<ng-template mat-tab-label>
<tabler-icon name="wallet" class="m-r-10 icon-24"></tabler-icon>
<span class="tab-label f-s-18 f-w-500">Payments</span>
</ng-template>
</mat-tab>
<mat-tab>
<ng-template mat-tab-label>
<tabler-icon name="app-window" class="m-r-10 icon-24"></tabler-icon>
<span class="tab-label f-s-18 f-w-500">Embedding</span>
</ng-template>
</mat-tab>
<mat-tab>
<ng-template mat-tab-label>
<tabler-icon name="arrow-fork" class="m-r-10 icon-24"></tabler-icon>
<span class="tab-label f-s-18 f-w-500">Workflows</span>
</ng-template>
</mat-tab>
</mat-tab-group>
<!-- Tab content shown BELOW the tab group -->
<div class="row tab-header-content p-y-66 align-items-center">
<div class="col-md-6">
<div class="tabsimage">
<img src="assets/images/landingpage/background/accordian1.jpg" alt="slider-group" class="img-fluid w-100" />
</div>
</div>
<div class="col-md-6 m-t-30">
<div class="right-content m-l-24">
<h2 class="f-s-40 lh-lg section-sub-title">Defend your focus</h2>
<div class="m-y-30">
<mat-accordion multi>
<!-- Panel 0 -->
<mat-expansion-panel #panel0 [expanded]="selectedIndex === 0 || selectedIndex === 3" hideToggle
class="expansion-panel">
<mat-expansion-panel-header>
<div class="d-flex align-items-center justify-content-between w-100">
<span class="f-s-18 f-w-500">Factor in outside colleagues</span>
<tabler-icon [name]="panel0.expanded ? 'minus' : 'plus'" class="m-l-8 icon-20"></tabler-icon>
</div>
</mat-expansion-panel-header>
<div>
<p class="f-s-16 m-y-0">
Factor in availability for required attendees, and skip
checking for conflicts for optional attendees.
</p>
</div>
</mat-expansion-panel>
<!-- Panel 1 -->
<mat-expansion-panel #panel1 [expanded]="selectedIndex === 1" hideToggle class="expansion-panel">
<mat-expansion-panel-header>
<div class="d-flex align-items-center justify-content-between w-100">
<span class="f-s-18 f-w-500">Combine teammate schedules</span>
<tabler-icon [name]="panel1.expanded ? 'minus' : 'plus'" class="icon-20"></tabler-icon>
</div>
</mat-expansion-panel-header>
<div>
<p class="f-s-16 m-y-0">
Factor in availability for required attendees, and skip
checking for conflicts for optional attendees.
</p>
</div>
</mat-expansion-panel>
<!-- Panel 2 & 3 merged -->
<mat-expansion-panel #panel2 [expanded]="selectedIndex === 2" hideToggle class="expansion-panel">
<mat-expansion-panel-header>
<div class="d-flex align-items-center justify-content-between w-100">
<span class="f-s-18 f-w-500">Round robin pooling</span>
<tabler-icon [name]="panel2.expanded ? 'minus' : 'plus'" class="m-l-8 icon-20"></tabler-icon>
</div>
</mat-expansion-panel-header>
<div>
<p class="f-s-16 m-y-0">
Factor in availability for required attendees, and skip
checking for conflicts for optional attendees.
</p>
</div>
</mat-expansion-panel>
</mat-accordion>
</div>
<a mat-flat-button color="primary">Learn More</a>
</div>
</div>
</div>
</div>
</div>
<div class="our-leadership spacing-top p-b-48">
<app-image-slider></app-image-slider>
</div>
<div class="toolBar bg-primary p-y-16">
<div class="container">
<div class="d-flex align-items-center justify-content-center">
<div class="social-chips flex-shrink-0">
<img src="assets/images/profile/user-2.jpg" width="44" height="44" alt="social"
class="rounded-circle m-x-1" />
<img src="assets/images/profile/user-3.jpg" width="44" height="44" alt="social"
class="rounded-circle m-x-1" />
</div>
<span class="text-white f-s-16 m-l-16">
Save valuable time and effort spent searching for a solution.
<a class="text-white f-w-600 m-l-8" href="#">Contact us now</a>
</span>
</div>
</div>
</div>
<div class="template-slider spacing-top-bottom">
<div class="custom-container">
<div class="bg-light-primary rounded-pill spacing-top-bottom template-slider-content">
<div class="spacing-left-right m-b-8">
<h2 class="f-s-40 lh-normal section-sub-title">
Discover Powerful Dozens of <br> Purpose-Fit Templates
</h2>
</div>
<div class="demo-slider overflow-hidden d-flex gap-30 spacing-bottom">
<div>
<div class="demo-slide">
<a [routerLink]="['/apps/chat']">
<img src="assets/images/front-pages/app-chat.jpg" alt="slide" class="img-fluid rounded-7 sliderImg" />
</a>
</div>
</div>
<div>
<div class="demo-slide">
<a (click)="onImageClick('/apps/email/inbox')">
<img src="assets/images/front-pages/app-email.jpg" alt="slide" class="img-fluid rounded-7 sliderImg"
[ngClass]="{
'img-border': selectedPath === '/apps/email/inbox'
}" />
</a>
</div>
</div>
<div>
<div class="demo-slide">
<a (click)="onImageClick('/dashboards/dashboard1')">
<img src="assets/images/front-pages/demo-main.jpg" alt="slide" class="img-fluid rounded-7 sliderImg"
[ngClass]="{
'img-border': selectedPath === '/dashboards/dashboard1'
}" />
</a>
</div>
</div>
<div>
<div class="demo-slide">
<img src="assets/images/front-pages/demo-dark.jpg" alt="slide" class="img-fluid rounded-7 sliderImg" />
</div>
</div>
<div>
<div class="demo-slide">
<a (click)="onImageClick('/front-pages/homepage')">
<img src="assets/images/front-pages/demo-horizontal.jpg" alt="slide"
class="img-fluid rounded-7 sliderImg" [ngClass]="{
'img-border': selectedPath === '/front-pages/homepage'
}" />
</a>
</div>
</div>
<div>
<div class="demo-slide">
<img src="assets/images/front-pages/demo-rtl.jpg" alt="slide" class="img-fluid rounded-7 sliderImg" />
</div>
</div>
<div>
<div class="demo-slide">
<img src="assets/images/front-pages/app-chat.jpg" alt="slide" class="img-fluid rounded-7 sliderImg" />
</div>
</div>
<div>
<div class="demo-slide">
<img src="assets/images/front-pages/app-email.jpg" alt="slide" class="img-fluid rounded-7 sliderImg" />
</div>
</div>
</div>
<div class="spacing-left-right">
<div class="row">
<div class="col-md-4 text-center m-b-30">
<h3 class="f-s-18 m-b-16">High Customizability</h3>
<p class="f-s-14 m-0">
Tailor the dashboard to your exact needs. Customize layouts, color
schemes, and widgets effortlessly for a personalized user
experience.
</p>
</div>
<div class="col-md-4 text-center m-b-30">
<h3 class="f-s-18 m-b-16">Powerful Data Analytics</h3>
<p class="f-s-14 m-0">
Unlock the true potential of your data with our advanced analytics
tools. Gain valuable insights and make data-driven decisions with
ease.
</p>
</div>
<div class="col-md-4 text-center m-b-30">
<h3 class="f-s-18 m-b-16">Interactive Charts</h3>
<p class="f-s-14 m-0">
Visualize complex data sets beautifully with our interactive
graphs and charts. Quickly grasp trends and patterns for smarter
analysis.
</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="features spacing-bottom">
<div class="container">
<div class="row align-items-center justify-content-between">
<!--row-->
<div class="col-md-5 m-b-30">
<div class="client-margin">
<h2 class="lh-normal f-s-40 m-b-16 section-sub-title">
What our clients <br> think <img src="assets/images/front-pages/logoIcon.svg" alt="logo" />
about us?
</h2>
<p class="m-0">
Our users' feedback is a testament to our commitment to quality
and user satisfaction. Read what they have to say about their
journey with us.
</p>
</div>
</div>
<div class="col-md-5">
<mat-card class="cardWithShadow b-1 rounded-8 m-b-0 p-48">
<mat-card-content>
<mat-card-title class="f-s-24 f-w-600 m-b-24">Features availability</mat-card-title>
<div class="d-flex align-items-center gap-16 m-b-24">
<div>
<img [src]="currentUser().img" [alt]="currentUser().name" class="rounded-circle" width="40" />
</div>
<h6 class="f-s-14 f-w-600">{{ currentUser().name }}</h6>
</div>
<p class="f-s-14 m-b-16 m-t-0">
Our users' feedback is a testament to our commitment to quality
and user satisfaction. Read what they have to say about their
journey with us.
</p>
<mat-divider></mat-divider>
<div class="d-flex align-items-center gap-10 m-t-8">
<button class="bg-light icon-32 d-flex align-items-center justify-content-center" mat-icon-button
(click)="goPrev()">
<i-tabler name="chevron-left"
class="icon-18 d-flex align-items-center justify-content-center"></i-tabler>
</button>
<span class="f-s-14">{{ displayCount() }}</span>
<button class="bg-light icon-32 d-flex align-items-center justify-content-center" mat-icon-button
(click)="goNext()">
<i-tabler name="chevron-right"
class="icon-18 d-flex align-items-center justify-content-center"></i-tabler>
</button>
</div>
</mat-card-content>
</mat-card>
</div>
</div>
</div>
</div>
<div class="exceptional position-relative">
<div class="custom-container">
<div class="bg-light-primary rounded-8 exceptional-content spacing-top-bottom">
<div class="row justify-content-center">
<div class="col-md-6">
<h2 class="lh-normal text-center f-s-40 m-b-30 section-sub-title">
Enjoy unparalleled features & exceptional flexibility.
</h2>
</div>
</div>
<div class="m-t-0">
<div class="demo-slider overflow-hidden d-flex gap-30">
<div class="row flex-nowrap overflow-auto gap-20">
@for (followercard of followercardsfirst; track followercard.title)
{
<div class="col-2">
<mat-card class="cardWithShadow demo-slide rounded-8">
<mat-card-content>
<div class="d-flex align-items-center justify-content-center x-20">
<img [src]="followercard.imgSrc" alt="icon" />
<h6 class="m-0 f-w-500 f-s-14 m-x-8">
{{ followercard.title }}
</h6>
</div>
</mat-card-content>
</mat-card>
</div>
}
</div>
</div>
<div class="demo-slider overflow-hidden d-flex gap-30 m-t-2">
<div class="row flex-nowrap overflow-auto gap-20">
@for (followercard of followercardsecond; track followercard.title)
{
<div class="col-2">
<mat-card class="cardWithShadow demo-slide-two rounded-8">
<mat-card-content>
<div class="d-flex align-items-center justify-content-center x-20">
<img [src]="followercard.imgSrc" alt="icon" />
<h6 class="m-0 f-w-500 f-s-14 m-x-8">
{{ followercard.title }}
</h6>
</div>
</mat-card-content>
</mat-card>
</div>
}
</div>
</div>
<div class="demo-slider overflow-hidden d-flex gap-30 m-t-2">
<div class="row flex-nowrap overflow-auto gap-20">
@for (followercard of followercardthird; track followercard.title) {
<div class="col-2">
<mat-card class="cardWithShadow demo-slide rounded-8">
<mat-card-content>
<div class="d-flex align-items-center justify-content-center x-20">
<img [src]="followercard.imgSrc" alt="icon" />
<h6 class="m-0 f-w-500 f-s-14 m-x-8">
{{ followercard.title }}
</h6>
</div>
</mat-card-content>
</mat-card>
</div>
}
</div>
</div>
</div>
</div>
</div>
</div>
<div class="asked-questions spacing-top-bottom">
<div class="container">
<h2 class="f-s-40 text-center lh-normal m-b-48 section-sub-title">Frequently Asked Questions</h2>
<div class="row align-items-center justify-content-center">
<div class="col-md-8">
<mat-accordion multi class="faq-accordion m-b-48 d-block">
@for (item of faqList; track item) {
<mat-expansion-panel [expanded]="expandedIndex === $index" (opened)="expandedIndex = $index"
(closed)="expandedIndex = null" hideToggle class="b-1 expansion-panel m-b-16">
<mat-expansion-panel-header>
<mat-panel-title class="f-s-18 m-x-0">{{
item.question
}}</mat-panel-title>
<tabler-icon [name]="expandedIndex === $index ? 'minus' : 'plus'" class="m-s-auto icon-20 m-x-0 p-0">
</tabler-icon>
</mat-expansion-panel-header>
<p class="m-0">{{ item.answer }}</p>
</mat-expansion-panel>
}
</mat-accordion>
</div>
</div>
<div class="d-flex justify-content-center">
<div class="d-flex align-items-center justify-content-center gap-4 p-y-6 p-x-10 rounded border-dash">
<span class="f-s-14">Still have a question?</span>
<a target="_blank" href="https://discord.com/invite/XujgB8ww4n"
class="text-decoration-underline text-dark f-s-14">Ask on discord</a>
<span class="f-s-14">or</span>
<a target="_blank" href="https://adminmart.com/support/"
class="text-decoration-underline text-dark f-s-14">Submit a ticket</a>
</div>
</div>
</div>
</div>
<div class="footer">
<div>
<app-footer></app-footer>
</div>
</div>
</div>

View File

@@ -0,0 +1,189 @@
.home-page {
.custom-container {
max-width: 1400px;
margin: 0 auto;
width: 100%;
padding: 0 15px;
}
.home-page-header {
.header-container-content {
.cardPosition {
.float-image {
animation: floatUpDown 6s ease-in-out infinite;
}
}
.cardPositionTwo {
.float-image {
animation: floatUpDown 6s ease-in-out infinite;
}
}
.loginBtn {
.play-button {
background-color: transparent;
border: 2px solid var(--mat-sys-primary); // or use your theme color
color: var(--mat-sys-primary);
box-shadow: none;
}
.textSee {
cursor: pointer;
&:hover {
color: var(--mat-sys-primary);
}
}
}
}
}
.dashboardCards {
.card-container {
mat-card-content {
padding: 0px !important;
}
}
}
.tab-header {
box-shadow: 0px 6px 12px rgba(127, 145, 156, 0.12);
.profileTabs {
background-color: var(--mdc-elevated-card-container-color) !important;
.mat-mdc-tab.mdc-tab-indicator--active {
.mdc-tab__text-label {
color: var(--mat-sys-primary);
}
}
}
}
.template-slider {
.template-slider-content {
.demo-slider {
.demo-slide {
animation: slide3d 15s linear infinite;
}
}
}
}
.features {
.cardWithShadow {
mat-card-content {
padding: 0px !important;
}
}
}
.exceptional {
.exceptional-content {
.demo-slider {
.demo-slide {
animation: slide3d 20s linear infinite;
}
.demo-slide-two {
animation: slide3dTwo 20s linear infinite;
}
}
}
}
.expansion-panel {
box-shadow: none;
background: transparent;
border-radius: 0 !important;
border-bottom: 1px solid var(--mat-sys-outline);
.mat-expansion-panel-header {
padding: 18px 0 !important;
height: auto;
}
}
.sliderImg {
max-width: 380px;
height: 300px;
}
.img-border {
border: 2px solid var(--mat-sys-secondary);
/* Blue border, change color as needed */
cursor: pointer;
}
.img-border:hover {
border-color: var(--mat-sys-secondary);
}
.border-dash {
border: 1px dashed var(--mat-sys-outline); // Initial border color (Bootstrap primary)
transition: border-color 0.3s ease;
flex-wrap: wrap;
&:hover {
border-color: var(--mat-sys-primary); // Use your Angular Material primary variable or a custom color
}
}
.faq-accordion {
.mat-expansion-panel {
border-radius: 8px !important;
.mat-expansion-panel-header {
padding: 20px 21px !important;
}
}
}
}
@keyframes floatUpDown {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(-6px); // smaller bounce
}
}
@keyframes slide3d {
from {
transform: translate3d(0, 0, 0);
}
to {
transform: translate3d(-2028px, 0, 0); // adjust based on actual slide width
}
}
@keyframes slide3dTwo {
from {
transform: translate3d(-2028px, 0, 0); // Rightward (starts left)
}
to {
transform: translate3d(0, 0, 0);
}
}
@media (max-width: 1199px) {
.home-page-header {
padding-bottom: 48px;
}
}

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { HomepageDetailsComponent } from './homepage-details.component';
describe('HomepageDetailsComponent', () => {
let component: HomepageDetailsComponent;
let fixture: ComponentFixture<HomepageDetailsComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [HomepageDetailsComponent]
})
.compileComponents();
fixture = TestBed.createComponent(HomepageDetailsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,131 @@
import { Component, computed, DestroyRef, inject, signal } from '@angular/core';
import { IconModule } from 'src/app/icon/icon.module';
import { MaterialModule } from 'src/app/material.module';
import {
faqList,
followercardsFirst,
followercardSecond,
followercardThird,
frameworks,
tiles,
users,
topcardsGrid,
} from '../front-pagesData';
import { CommonModule } from '@angular/common';
import { MediaMatcher } from '@angular/cdk/layout';
import { ImageSliderComponent } from '../image-slider/image-slider.component';
import { FooterComponent } from '../footer/footer.component';
import { MatDialog } from '@angular/material/dialog';
import { TemplateVideoComponent } from '../template-video/template-video.component';
import { Router, RouterModule } from '@angular/router';
@Component({
selector: 'app-homepage-details',
imports: [
MaterialModule,
IconModule,
CommonModule,
ImageSliderComponent,
FooterComponent,
RouterModule
],
templateUrl: './homepage-details.component.html',
styleUrl: './homepage-details.component.scss',
})
export class HomepageDetailsComponent {
topcards=topcardsGrid;
centered = false;
disabled = false;
unbounded = false;
radius: number;
color: string;
showBackground: boolean = false;
frameworks = frameworks;
selectedIndex = 1;
readonly dialog = inject(MatDialog);
private router = inject(Router);
private destroyRef = inject(DestroyRef); // ✅ For automatic cleanup
private mediaMatcher = inject(MediaMatcher); // ✅ Proper MediaMatcher injection
mobileQuery: MediaQueryList;
isMobileView = false;
readonly panelOpenState = signal(false);
tiles = tiles;
hideCloserBtn: boolean = true;
users = users;
expandedIndex: number | null = null;
currentIndex = signal(0); // Starting from 0
faqList = faqList;
selectedPath: string | null = null;
clicked = false;
followercardsfirst = followercardsFirst;
followercardsecond = followercardSecond;
followercardthird = followercardThird;
currentUser = computed(() => this.users[this.currentIndex()]);
displayCount = computed(() => `${this.currentIndex() + 1}/${this.users.length}`);
constructor() {
const isSmallScreen = this.mediaMatcher.matchMedia('(max-width: 599px)');
// ✅ Setup media query for max-width: 1199px
this.mobileQuery = this.mediaMatcher.matchMedia('(max-width: 1199px)');
this.isMobileView = this.mobileQuery.matches;
const listener = (e: MediaQueryListEvent) => {
this.isMobileView = e.matches;
};
// ✅ Listen to viewport changes
this.mobileQuery.addEventListener('change', listener);
// ✅ Clean up listener on component destroy
this.destroyRef.onDestroy(() => {
this.mobileQuery.removeEventListener('change', listener);
});
}
isOver(): boolean {
return this.mediaMatcher.matchMedia('(max-width: 1199px)').matches;
}
goPrev() {
if (this.currentIndex() > 0) {
this.currentIndex.update((i) => i - 1);
}
}
goNext() {
if (this.currentIndex() < this.users.length - 1) {
this.currentIndex.update((i) => i + 1);
}
}
openDialog(showBackground:boolean){
this.showBackground = showBackground;
const dialogRef = this.dialog.open(TemplateVideoComponent, {
data: {},
width: '1000px',
});
dialogRef.afterClosed().subscribe((result) => {
if (result === false) {
this.showBackground = false; // Reset or take any action
}
});
}
onImageClick(path: string) {
this.selectedPath = path;
setTimeout(() => {
this.router.navigate([path]);
}, 100); // brief delay to show border
}
}

View File

@@ -0,0 +1,137 @@
<div>
<mat-sidenav-container>
<mat-sidenav-content class="landing-page">
@if(hideCloserBtn){
<mat-toolbar
class="bg-primary d-flex justify-content-between align-items-center heightToolbar position-relative overflow-hidden">
<!-- Center text -->
<div class="text-center text-white f-s-14 f-w-500 flex-grow-1">
<span class="text-white bg-secondary m-x-12 f-s-12 p-x-8 p-y-4 rounded">New</span>
Frontend Pages Included!
</div>
<!-- Right close icon -->
<button mat-icon-button aria-label="Close" class="text-white" (click)="hideCloser()">
<mat-icon>close</mat-icon>
</button>
</mat-toolbar>
}
<mat-toolbar class="topbar front-topbar topbar-xl m-auto bg-light-primary p-y-8"
[ngClass]="{ 'fixed-topbar': isTopbarFixed }">
<div class="custom-container full-width">
<div class="d-flex align-items-center justify-content-between">
<div class="branding p-x-0">
<app-branding></app-branding>
</div>
@if(!isMobileView){
<div class="d-none d-lg-flex justify-content-between toolBarContent">
<button mat-button class="m-x-8 f-s-15 f-w-500 nav-item" [routerLink]="['/front-pages/about']"
[class.selected]="isActiveRoute('about')">
About Us
</button>
<button mat-button class="m-x-8 f-s-14 f-w-500 nav-item" [class.selected]="isActiveRoute('blog')"
[routerLink]="['/front-pages/blog']">
Blogs
</button>
<button mat-button class="m-x-8 f-s-15 f-w-500 nav-item" [routerLink]="['/front-pages/portfolio']"
[class.selected]="isActiveRoute('portfolio')">
Portfolio
<span class="bg-light-primary text-primary rounded f-w-600 p-x-8 p-y-4 f-s-12 m-l-4">
New
</span>
</button>
<button mat-button class="m-x-8 f-s-15 f-w-500 nav-item" [class.selected]="isActiveRoute('dashboard')"
[routerLink]="['/dashboards/dashboard1']">
Dashboard
</button>
<button mat-button class="m-x-8 f-s-15 f-w-500 nav-item" [class.selected]="isActiveRoute('pricing')"
[routerLink]="['/front-pages/pricing']">
Pricing
</button>
<button mat-button class="m-x-8 f-s-15 f-w-500 nav-item" [class.selected]="isActiveRoute('contact')"
[routerLink]="['/front-pages/contact']">
Contact
</button>
</div>
<a mat-flat-button color="primary" class="" [routerLink]="'/authentication/login'">Login</a>
} @if(isMobileView){
<button mat-mini-fab class="bg-light" aria-label="Example icon button with a delete icon"
(click)="customizerRight.toggle()">
<i-tabler class="icon-18 d-flex" name="menu"></i-tabler>
</button>
}
</div>
</div>
</mat-toolbar>
<div class="content-scroll">
<router-outlet></router-outlet>
</div>
</mat-sidenav-content>
<mat-sidenav class="mobile-sidebar" #customizerRight mode="over" position="start">
<div class="">
<div class="branding">
<app-branding></app-branding>
</div>
<div class="">
<mat-list role="list">
<mat-list-item role="listitem">
<button mat-button class="text-dark" [routerLink]="['/front-pages/about']"
[class.selected]="isActiveRoute('about')">
About Us
</button></mat-list-item>
<mat-list-item role="listitem">
<button mat-button class="text-dark" [class.selected]="isActiveRoute('blogs')"
[routerLink]="['/front-pages/blog']">
Blogs
</button></mat-list-item>
<mat-list-item role="listitem">
<button mat-button class="text-dark" [routerLink]="['/front-pages/portfolio']"
[class.selected]="isActiveRoute('portfolio')">
Portfolio
<span class="bg-light-primary text-primary rounded f-w-600 p-6 p-y-4 f-s-12">
New
</span>
</button></mat-list-item>
<mat-list-item role="listitem">
<button mat-button class="text-dark" [class.selected]="isActiveRoute('dashboard')"
[routerLink]="['/dashboards/dashboard1']">
Dashboard
</button>
</mat-list-item>
<mat-list-item role="listitem">
<button mat-button class="text-dark" [class.selected]="isActiveRoute('pricing')"
[routerLink]="['/front-pages/pricing']">
Pricing
</button>
</mat-list-item>
<mat-list-item role="listitem">
<button mat-button class="text-dark " [class.selected]="isActiveRoute('contact')"
[routerLink]="['/front-pages/contact']">
Contact
</button></mat-list-item>
<mat-list-item role="listitem" class="w-100">
<a mat-flat-button color="primary" class="w-100" [routerLink]="'/authentication/login'">Get
Started</a></mat-list-item>
</mat-list>
</div>
</div>
</mat-sidenav>
</mat-sidenav-container>
@if(showBackToTop){
<div
class="back-to-top bg-primary rounded-circle d-flex align-items-center justify-content-center shadow icon-54 cursor-pointer"
(click)="scrollToTop()">
<i-tabler name="arrow-up" class="icon-24 text-white"></i-tabler>
</div>
}
</div>

View File

@@ -0,0 +1,32 @@
.landing-page {
.custom-container {
max-width: 1400px;
margin: 0 auto;
width: 100%;
padding: 0 15px;
}
.heightToolbar {
height: 46px;
background-size: cover;
background-repeat: no-repeat;
background-image: url(../../../../assets/images/front-pages/topbar-bg.png);
}
.toolBarContent {
.nav-item {
&.selected {
background-color: var(--mat-sys-primary-fixed-dim);
color: var(--mat-sys-primary); // optional for visibility
transition: background-color 0.3s ease;
}
&:hover {
color: var(--mat-sys-primary);
transition: color 0.3s ease;
}
}
}
}

View File

@@ -0,0 +1,65 @@
import { MediaMatcher } from '@angular/cdk/layout';
import { CommonModule } from '@angular/common';
import { Component, HostListener, inject, ViewChild } from '@angular/core';
import { MatSidenav } from '@angular/material/sidenav';
import { ActivatedRoute, Router, RouterLink, RouterOutlet } from '@angular/router';
import { IconModule } from 'src/app/icon/icon.module';
import { BrandingComponent } from 'src/app/layouts/full/vertical/sidebar/branding.component';
import { MaterialModule } from 'src/app/material.module';
@Component({
selector: 'app-homepage',
imports: [MaterialModule, BrandingComponent, RouterLink,
IconModule, RouterOutlet, CommonModule],
templateUrl: './homepage.component.html',
styleUrl: './homepage.component.scss'
})
export class HomepageComponent {
@ViewChild('customizerRight') customizerRight!: MatSidenav;
selected: string = ''; // default selected
mobileQuery: MediaQueryList;
isMobileView = false;
hideCloserBtn: boolean = true;
private router = inject(Router)
private mediaMatcher: MediaQueryList = matchMedia(`(max-width: 1199px)`);
showBackToTop: boolean;
isTopbarFixed: boolean;
constructor(private route: ActivatedRoute) {
const media = inject(MediaMatcher);
this.mobileQuery = media.matchMedia('(max-width: 1199px)');
this.isMobileView = this.mobileQuery.matches;
this.mobileQuery.addEventListener('change', (e) => {
this.isMobileView = e.matches;
this.closeSidenavIfNeeded();
});
}
closeSidenavIfNeeded() {
if (!this.isMobileView && this.customizerRight?.opened) {
this.customizerRight.close();
}
}
isOver(): boolean {
return this.mediaMatcher.matches;
}
isActiveRoute(route: string): boolean {
return this.router.url.includes(`/front-pages/${route}`);
}
hideCloser() {
this.hideCloserBtn = false;
}
getNavigate() {
this.router.navigate(['/dashboards/dashboard1'])
}
scrollToTop(): void {
window.scrollTo({ top: 0, behavior: 'smooth' });
}
@HostListener('window:scroll', [])
onWindowScroll() {
this.showBackToTop = window.scrollY > 300;
this.isTopbarFixed = scrollY > 45;
}
}

View File

@@ -0,0 +1,44 @@
<div class="img-slider-content">
<div class="container img-slider">
<div class="">
<div class="row m-b-48">
<div class="col-md-5">
<h2 class="f-s-40 lh-lg m-b-24 section-sub-title">Our leadership</h2>
<div class="d-flex justify-content-between align-items-center">
<p class="m-0">
Our robust analytics offer rich insights into the information
buyers want, informing where teams
</p>
</div>
</div>
<div class="col-md-7 m-t-24 position-relative d-flex flex-column justify-content-end align-items-end">
<div class="d-flex gap-16">
<button mat-icon-button class="d-flex align-items-center justify-content-center icon-48 bg-light" aria-label="Previous" (click)="prev()">
<i-tabler name="arrow-left" class="d-flex align-items-center justify-content-center"></i-tabler>
</button>
<button mat-icon-button class="d-flex align-items-center justify-content-center icon-48 bg-light" aria-label="Next" (click)="next()">
<i-tabler name="arrow-right" class="d-flex align-items-center justify-content-center"></i-tabler>
</button>
</div>
</div>
</div>
<div class="row">
@for (member of visibleTeamMembers(); track member.id){
<div class="col-sm-6 col-md-3">
<mat-card class="cardWithShadow productcard overflow-hidden rounded-8 position-relative shadow-none">
<a routerLink="/widgets/cards">
<img [src]="member.image" alt="imgSrc" class="w-100 h-100 rounded-7" mat-card-image />
</a>
<mat-card class="position-absolute info-card text-center p-y-16 p-x-10">
<h3 class="f-w-600 m-b-8">{{ member.name }}</h3>
<p class="f-s-14 m-y-0">{{ member.position }}</p>
</mat-card>
</mat-card>
</div>
}
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,22 @@
.img-slider-content {
.img-slider {
.mat-mdc-card {
margin-bottom: 0px !important;
}
.productcard {
position: relative;
.info-card {
bottom: 42px; // controls overlap depth
left: 50%;
transform: translateX(-50%);
width: 90%;
box-shadow: 0px 6px 12px rgba(127, 145, 156, 0.12);
z-index: 2;
}
}
}
}

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ImageSliderComponent } from './image-slider.component';
describe('ImageSliderComponent', () => {
let component: ImageSliderComponent;
let fixture: ComponentFixture<ImageSliderComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ImageSliderComponent]
})
.compileComponents();
fixture = TestBed.createComponent(ImageSliderComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,39 @@
import { Component, computed, signal } from '@angular/core';
import { IconModule } from 'src/app/icon/icon.module';
import { MaterialModule } from 'src/app/material.module';
import { team } from '../front-pagesData';
@Component({
selector: 'app-image-slider',
imports: [MaterialModule,IconModule],
templateUrl: './image-slider.component.html',
styleUrl: './image-slider.component.scss'
})
export class ImageSliderComponent {
team = team;
// Signals
currentPage = signal(0);
pageSize = 4;
visibleTeamMembers = computed(() => {
const start = this.currentPage() * this.pageSize;
const end = start + this.pageSize;
return this.team.slice(start, end);
});
next() {
console.log('next--->',this.visibleTeamMembers().map(m => m.id));
const totalPages = Math.ceil(this.team.length / this.pageSize);
if (this.currentPage() < totalPages - 1) {
this.currentPage.update((p) => p + 1);
}
}
prev() {
console.log(this.visibleTeamMembers().map(m => m.id));
if (this.currentPage() > 0) {
this.currentPage.update((p) => p - 1);
}
}
}

View File

@@ -0,0 +1,68 @@
<div class="row justify-content-center">
<div class="col-lg-7 col-sm-11">
<h2 class="f-s-40 text-center m-b-48 lh-normal section-sub-title">
111,476+ Trusted developers & many tech giants as well
</h2>
</div>
</div>
<div class="row">
@for(plan of plans;track plan){
<div class="col-lg-3 col-md-4 col-sm-6">
<mat-card class="cardWithShadow b-1">
<mat-card-content>
<div class="m-b-16 d-flex align-items-center">
<h6 class="f-s-20 f-w-600 ">
{{ plan.title }}
@if (plan.popular) {
<span class="bg-light-primary text-primary rounded f-w-600 f-s-12 p-y-2 p-x-8">
Popular
</span>
}
</h6>
</div>
<p class="f-s-12 m-b-32 m-t-0">{{ plan.description }}</p>
<mat-divider></mat-divider>
<div class="price-line m-t-32">
<span class="f-s-40 f-w-600">${{ plan.price }}</span>
<span class="f-s-14">/{{ plan.period }}</span>
</div>
<div class="m-y-32">
@for(feature of plan.features; track feature) {
<div class="d-flex align-items-center gap-8 m-b-12">
<img
[src]="feature.included ? '/assets/images/front-pages/icon-circle-check.svg' : '/assets/images/front-pages/icon-circle-x.svg'"
alt="icon-facebook-dark" width="21" height="21" />
<span [ngClass]="{
'f-w-600': feature.bold,
'f-s-14 op-5': !feature.included,
'f-s-14': feature.included
}">
{{ feature.text }}
</span>
</div>
}
</div>
<button mat-flat-button color="primary" class="w-100 ">
Purchase Now
</button>
</mat-card-content>
</mat-card>
</div>
}
</div>
<div class="m-t-32">
<p class="text-center f-s-14 m-b-0">Secured payment with PayPal & Razorpay</p>
<div class="d-flex align-items-center justify-content-center m-t-32 m-x-0 gap-48 flex-wrap">
@for( logo of paymentLogos;track logo){
<img class="cursor-pointer" [src]="logo.src" [alt]="logo.alt" [matTooltip]="logo.tooltip"
matTooltipPosition="below">
}
</div>
</div>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PagePricingComponent } from './page-pricing.component';
describe('PagePricingComponent', () => {
let component: PagePricingComponent;
let fixture: ComponentFixture<PagePricingComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [PagePricingComponent]
})
.compileComponents();
fixture = TestBed.createComponent(PagePricingComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,17 @@
import { CommonModule } from '@angular/common';
import { Component } from '@angular/core';
import { IconModule } from 'src/app/icon/icon.module';
import { MaterialModule } from 'src/app/material.module';
import { paymentLogos, plans } from '../front-pagesData';
@Component({
selector: 'app-page-pricing',
imports: [MaterialModule, IconModule, CommonModule],
templateUrl: './page-pricing.component.html',
styleUrl: './page-pricing.component.scss',
})
export class PagePricingComponent {
plans = plans;
paymentLogos = paymentLogos;
}

View File

@@ -0,0 +1,57 @@
<div class="banner-section bg-light-primary spacing-top-bottom">
<div class="container">
<p class="text-primary text-center text-uppercase f-s-14 m-t-0">
Portfolio
</p>
<h1 class="text-center f-s-48 section-sub-title lh-normal">Explore Our Latest Works</h1>
</div>
</div>
<div class="spacing-top-bottom">
<div class="container">
<div class="d-flex align-items-center justify-content-between gap-3 flex-wrap m-b-24">
<div class="d-flex align-items-center gap-8 m-b-10">
<h5 class="f-w-500 f-s-20">Portfolio</h5>
<div class="p-x-6 p-y-2 rounded-pill bg-secondary text-white">
<div class="f-s-14 lh-sm">{{ filteredCount }} </div>
</div>
</div>
<!-- Search bar pushed to the right -->
<mat-form-field appearance="outline" class="search-bar-style hide-hint">
<mat-icon matPrefix>search</mat-icon>
<input matInput placeholder="Search Photos" [(ngModel)]="searchText" (input)="onSearchChange()" />
</mat-form-field>
</div>
<div class="row">
@for(productcard of filteredCardImgs; track productcard.id) {
<div class="col-sm-6 col-lg-4">
<mat-card class="cardWithShadow productcard overflow-hidden b-1 rounded">
<a routerLink="/widgets/cards">
<img src="{{ productcard.imgSrc }}" alt="imgSrc" class="w-100 object-cover" height="220" mat-card-image />
</a>
<mat-card-content class="p-b-24 p-t-12 position-relative">
<mat-card-title class="mat-headline-2 f-s-16 m-b-4">
<div class="d-flex align-items-center justify-content-between">
<!-- Left Side: Text Content -->
<div>
<h6 class="f-s-16 lh-sm f-w-600">{{ productcard.title }}</h6>
<p class="f-s-12 f-w-400 m-y-0">{{ productcard.date }}</p>
</div>
<!-- Right Side: Icon -->
<button mat-icon-button aria-label="Example icon button with a vertical three dot icon">
<mat-icon>more_vert</mat-icon>
</button>
</div>
</mat-card-title>
</mat-card-content>
</mat-card>
</div>
}
</div>
</div>
</div>
<div class="footer">
<app-footer></app-footer>
</div>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PortfolioComponent } from './portfolio.component';
describe('PortfolioComponent', () => {
let component: PortfolioComponent;
let fixture: ComponentFixture<PortfolioComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [PortfolioComponent]
})
.compileComponents();
fixture = TestBed.createComponent(PortfolioComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,37 @@
import { Component, OnInit } from '@angular/core';
import { IconModule } from 'src/app/icon/icon.module';
import { MaterialModule } from 'src/app/material.module';
import { productcards } from '../front-pagesData';
import { FooterComponent } from '../footer/footer.component';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-portfolio',
imports: [MaterialModule, IconModule, FooterComponent, CommonModule, FormsModule],
templateUrl: './portfolio.component.html',
styleUrl: './portfolio.component.scss'
})
export class PortfolioComponent implements OnInit {
filteredCards = productcards;
searchText: string = '';
filteredCardImgs = [...this.filteredCards]; // Initialize with full data
filteredCount: number = this.filteredCardImgs.length;
ngOnInit(): void {
console.log('filteredCards', this.filteredCards)
}
onSearchChange() {
const query = this.searchText.toLowerCase().trim();
this.filteredCardImgs = this.filteredCards.filter(item =>
item.title.toLowerCase().includes(query) ||
item.date.toLowerCase().includes(query)
);
this.filteredCount = this.filteredCardImgs.length; // ✅ update the count here
}
}

View File

@@ -0,0 +1,18 @@
<div class="banner-section bg-light-primary spacing-top-bottom">
<div class="container">
<p class="text-primary text-center text-uppercase f-s-14 m-t-0">
Pricing Page
</p>
<h1 class="text-center f-s-48 section-sub-title lh-normal">Choose Your Plan</h1>
</div>
</div>
<div class="page-pricing spacing-top-bottom">
<div class="container">
<app-page-pricing></app-page-pricing>
</div>
</div>
<div class="footer">
<app-footer></app-footer>
</div>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PricingComponent } from './pricing.component';
describe('PricingComponent', () => {
let component: PricingComponent;
let fixture: ComponentFixture<PricingComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [PricingComponent]
})
.compileComponents();
fixture = TestBed.createComponent(PricingComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,15 @@
import { Component } from '@angular/core';
import { IconModule } from 'src/app/icon/icon.module';
import { MaterialModule } from 'src/app/material.module';
import { FooterComponent } from '../footer/footer.component';
import { PagePricingComponent } from '../page-pricing/page-pricing.component';
@Component({
selector: 'app-pricing',
imports: [MaterialModule,IconModule,FooterComponent,PagePricingComponent],
templateUrl: './pricing.component.html',
styleUrl: './pricing.component.scss'
})
export class PricingComponent {
}

View File

@@ -0,0 +1,11 @@
<mat-dialog-content class="p-b-0">
<iframe width="100%" height="500" src="https://www.youtube.com/embed/n-J3dDy1kro?si=k441rPIuc1bmKXJ9" frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen
class="rounded-8"></iframe>
</mat-dialog-content>
<div mat-dialog-actions>
<!-- <button mat-flat-button> Close</button> -->
<button mat-flat-button class="bg-light text-primary" (click)="closeDialog()">
Close
</button>
</div>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TemplateVideoComponent } from './template-video.component';
describe('TemplateVideoComponent', () => {
let component: TemplateVideoComponent;
let fixture: ComponentFixture<TemplateVideoComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [TemplateVideoComponent]
})
.compileComponents();
fixture = TestBed.createComponent(TemplateVideoComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,19 @@
import { Component } from '@angular/core';
import { IconModule } from 'src/app/icon/icon.module';
import { MaterialModule } from 'src/app/material.module';
import { MatDialogRef } from '@angular/material/dialog';
@Component({
selector: 'app-template-video',
imports: [MaterialModule,
IconModule,],
templateUrl: './template-video.component.html',
styleUrl: './template-video.component.scss'
})
export class TemplateVideoComponent {
constructor(private dialogRef: MatDialogRef<TemplateVideoComponent>){
}
closeDialog(): void {
this.dialogRef.close(false); // Pass false back to parent
}
}

View File

@@ -0,0 +1,69 @@
export const BASIC_SLIDE_TOGGLE_TS_SNIPPET = ` import {Component} from '@angular/core';
import {MatSlideToggleModule} from '@angular/material/slide-toggle';
/**
* @title slide-toggle
*/
@Component({
selector: 'app-slide-toggle',
imports: [MatSlideToggleModule],
templateUrl: './slide-toggle.component.html'
})
export class AppSlideToggleComponent {
constructor() {}
}
`;
export const FORM_SLIDE_TOGGLE_TS_SNIPPET = ` import {Component, inject} from '@angular/core';
import {MatSlideToggleModule} from '@angular/material/slide-toggle';
import {FormBuilder, FormGroup, Validators, FormsModule, ReactiveFormsModule} from '@angular/forms';
import {MatButtonModule} from '@angular/material/button';
import { MatSlideToggleModule} from '@angular/material/slide-toggle';
/**
* @title Slide-toggle with forms
*/
@Component({
selector: 'app-slide-toggle',
imports: [MatSlideToggleModule, FormsModule, MatButtonModule, ReactiveFormsModule,],
templateUrl: './slide-toggle.component.html'
})
export class AppSlideToggleComponent {
constructor() {}
private _formBuilder = inject(FormBuilder);
isChecked = true;
formGroup = this._formBuilder.group({
enableWifi: '',
acceptTerms: ['', Validators.requiredTrue],
});
alertFormValues(formGroup: FormGroup) {
alert(JSON.stringify(formGroup.value, null, 2));
}
}
`;
export const CONFIGURATION_SLIDE_TOGGLE_TS_SNIPPET = ` import {Component} from '@angular/core';
import {MatSlideToggleModule} from '@angular/material/slide-toggle';
import {MatCheckboxModule} from '@angular/material/checkbox';
import {FormsModule} from '@angular/forms';
import {MatRadioModule} from '@angular/material/radio';
import {MatCardModule} from '@angular/material/card';
/**
* @title Configurable slide-toggle
*/
@Component({
selector: 'app-slide-toggle',
imports: [MatCardModule, MatRadioModule, FormsModule, MatCheckboxModule, MatSlideToggleModule],
templateUrl: './slide-toggle.component.html'
})
export class AppSlideToggleComponent {
constructor() {}
checked = false;
disabled = false;
}
`;

View File

@@ -0,0 +1,63 @@
import { Component, OnInit, inject } from '@angular/core';
import {FormBuilder, FormGroup, Validators, ReactiveFormsModule} from '@angular/forms';
import {
MatSlideToggleModule,
// _MatSlideToggleRequiredValidatorModule,
} from '@angular/material/slide-toggle';
import {MatCheckboxModule} from '@angular/material/checkbox';
import {FormsModule} from '@angular/forms';
import {MatRadioModule} from '@angular/material/radio';
import {MatCardModule} from '@angular/material/card';
import {MatButtonModule} from '@angular/material/button';
import { AppCodeViewComponent } from 'src/app/components/code-view/code-view.component';
// snippets
import { BASIC_SLIDE_TOGGLE_HTML_SNIPPET, CONFIGURATION_SLIDE_TOGGLE_HTML_SNIPPET, FORM_SLIDE_TOGGLE_HTML_SNIPPET } from './code/slide-toggle-html-snippet';
import { BASIC_SLIDE_TOGGLE_TS_SNIPPET, CONFIGURATION_SLIDE_TOGGLE_TS_SNIPPET, FORM_SLIDE_TOGGLE_TS_SNIPPET } from './code/slide-toggle-ts-snippet';
import { Highlight, HighlightAuto } from 'ngx-highlightjs';
import { HighlightLineNumbers } from 'ngx-highlightjs/line-numbers';
@Component({
selector: 'app-slide-toggle',
imports: [MatCardModule, MatRadioModule, FormsModule, MatCheckboxModule, MatSlideToggleModule, ReactiveFormsModule, MatButtonModule,
// _MatSlideToggleRequiredValidatorModule
Highlight,
HighlightAuto,
HighlightLineNumbers,
AppCodeViewComponent,
],
templateUrl: './slide-toggle.component.html'
})
export class AppSlideToggleComponent implements OnInit {
// 1 [Basic with Slide Toggle]
codeForSlideToggleBasic = BASIC_SLIDE_TOGGLE_HTML_SNIPPET;
codeForSlideToggleBasicTs = BASIC_SLIDE_TOGGLE_TS_SNIPPET;
// 2 [Form with Slide Toggle]
codeForSlideToggleForm = FORM_SLIDE_TOGGLE_HTML_SNIPPET;
codeForSlideToggleFormTs = FORM_SLIDE_TOGGLE_TS_SNIPPET;
// 3 [Configuration with Slide Toggle]
codeForSlideToggleConfiguration = CONFIGURATION_SLIDE_TOGGLE_HTML_SNIPPET;
codeForSlideToggleConfigurationTs = CONFIGURATION_SLIDE_TOGGLE_TS_SNIPPET;
// configuration
checked = false;
disabled = false;
private _formBuilder = inject(FormBuilder);
isChecked = true;
formGroup = this._formBuilder.group({
enableWifi: '',
acceptTerms: ['', Validators.requiredTrue],
});
alertFormValues(formGroup: FormGroup) {
alert(JSON.stringify(formGroup.value, null, 2));
}
ngOnInit(): void {}
}

View File

@@ -0,0 +1,348 @@
<!-- --------------------------------------------------------------------- -->
<!-- card 1 -->
<!-- --------------------------------------------------------------------- -->
<div class="row">
@for(topcard of topcards; track topcard) {
<div class="col-lg-2 col-sm-4 col-6">
<mat-card class="shadow-none text-center bg-light-{{ topcard.color }} shadow-none">
<mat-card-content class="p-32">
<img [src]="topcard.img" alt="users" width="40" class="rounded-circle" />
<h4 class="f-s-14 f-w-600 text-{{ topcard.color }} m-t-8">
{{ topcard.title }}
</h4>
<h6 class="m-t-4 f-s-21 f-w-600 text-{{ topcard.color }} m-t-8">
{{ topcard.subtitle }}
</h6>
</mat-card-content>
</mat-card>
</div>
}
</div>
<!-- --------------------------------------------------------------------- -->
<!-- card 2 -->
<!-- --------------------------------------------------------------------- -->
<div class="row justify-content-center">
@for(cardimg of cardimgs; track cardimg.imgSrc) {
<div class="col-sm-6 col-lg-4">
<mat-card class="cardWithShadow card2 position-relative card-hover">
<img mat-card-image src="{{ cardimg.imgSrc }}" alt="Photo of a Shiba Inu" />
<div class="card-overlay h-100 d-flex align-items-end justify-content-end">
<mat-chip class="f-s-12 f-w-600 m-y-16 m-r-16 bg-white">{{
cardimg.time
}}</mat-chip>
</div>
<mat-card-content class="p-y-24">
<div class="user-category">
<div>
<img src="{{ cardimg.user }}" class="rounded-circle" width="40" />
</div>
<mat-chip class="f-s-12 m-y-16 f-w-600 bg-light">{{
cardimg.category
}}</mat-chip>
</div>
<mat-card-title>{{ cardimg.title }}</mat-card-title>
<div class="d-flex align-items-center justify-content-center m-t-24">
<div class="d-flex align-items-center">
<span class="m-r-12 f-s-14 d-flex align-items-center"><i-tabler name="eye"
class="icon-18 m-r-4"></i-tabler>{{ cardimg.views }}</span>
<span class="f-s-14 d-flex align-items-center"><i-tabler name="message-2"
class="icon-18 m-r-4"></i-tabler>{{ cardimg.comments }}</span>
</div>
<span class="m-l-auto f-s-14 d-flex align-items-center">
<i-tabler name="point" class="icon-14 m-r-4 d-flex"></i-tabler>
{{ cardimg.date }}
</span>
</div>
</mat-card-content>
</mat-card>
</div>
}
</div>
<!-- --------------------------------------------------------------------- -->
<!-- card 3 -->
<!-- --------------------------------------------------------------------- -->
<div class="row">
@for(productcard of productcards; track productcard.title) {
<div class="col-sm-6 col-lg-3">
<mat-card class="cardWithShadow productcard overflow-hidden">
<a routerLink="/widgets/cards">
<img src="{{ productcard.imgSrc }}" alt="imgSrc" class="w-100" mat-card-image />
</a>
<mat-card-content class="p-b-24 p-t-12 position-relative">
<button mat-mini-fab class="icon-30 m-t--48 d-flex bg-primary text-white" matTooltip="Add to Cart">
<i-tabler name="basket" class="icon-16 d-flex"></i-tabler>
</button>
<mat-card-title class="mat-headline-2 f-s-16 m-b-4 m-t-16">{{
productcard.title
}}</mat-card-title>
<div class="d-flex align-items-center justify-content-between">
<div class="d-flex align-items-center">
<h6 class="f-s-16 f-w-600">${{ productcard.price }}</h6>
<span class="f-s-14 m-l-4 text-decoration-line-through">${{ productcard.rprice }}</span>
</div>
<div class="m-l-auto d-flex gap-4">
<span><i-tabler name="star" class="fill-warning icon-18"></i-tabler></span>
<span><i-tabler name="star" class="fill-warning icon-18"></i-tabler></span>
<span><i-tabler name="star" class="fill-warning icon-18"></i-tabler></span>
<span><i-tabler name="star" class="fill-warning icon-18"></i-tabler></span>
<span><i-tabler name="star" class="fill-warning icon-18"></i-tabler></span>
</div>
</div>
</mat-card-content>
</mat-card>
</div>
}
</div>
<!-- --------------------------------------------------------------------- -->
<!-- card 4 -->
<!-- --------------------------------------------------------------------- -->
<div class="row">
@for(musiccard of musiccards; track musiccard.title) {
<div class="col-lg-4">
<mat-card class="cardWithShadow overflow-hidden">
<div class="row m-0">
<div class="col-6 p-24">
<h5 class="f-w-600 f-s-18 m-0">{{ musiccard.title }}</h5>
<span class="f-s-14">{{ musiccard.subtext }}</span>
<div class="d-flex align-items-center justify-content-between m-t-24">
<button mat-icon-button class="d-flex justify-content-center">
<i-tabler name="player-skip-back" class="icon-16 d-flex"></i-tabler>
</button>
<button mat-icon-button color="warn" class="d-flex justify-content-center">
<i-tabler name="player-play" class="icon-16 d-flex"></i-tabler>
</button>
<button mat-icon-button class="d-flex justify-content-center">
<i-tabler name="player-skip-forward" class="icon-16 d-flex"></i-tabler>
</button>
</div>
</div>
<div class="col-6">
<img src="{{ musiccard.imgSrc }}" width="240" height="180" class="h-100" alt="blog" />
</div>
</div>
</mat-card>
</div>
}
</div>
<!-- --------------------------------------------------------------------- -->
<!-- card 5 -->
<!-- --------------------------------------------------------------------- -->
<div class="row">
@for(followercard of followercards; track followercard.title) {
<div class="col-sm-6 col-lg-4">
<mat-card class="cardWithShadow">
<mat-card-content>
<div class="d-flex align-items-center">
<div class="d-flex align-items-center">
<img src="{{ followercard.imgSrc }}" width="40" alt="user" class="rounded-circle" />
<div class="m-l-16">
<h6 class="m-0 f-w-600 f-s-16">{{ followercard.title }}</h6>
<span class="d-flex align-items-center f-s-14"><i-tabler name="map-pin"
class="icon-14 m-r-4"></i-tabler>{{ followercard.subtext }}</span>
</div>
</div>
<button mat-flat-button color="primary" class="m-l-auto">
Follow
</button>
</div>
</mat-card-content>
</mat-card>
</div>
}
</div>
<!-- --------------------------------------------------------------------- -->
<!-- card 6 -->
<!-- --------------------------------------------------------------------- -->
<div class="row">
@for(friendcard of friendcards; track friendcard.title) {
<div class="col-sm-6 col-lg-3">
<mat-card class="cardWithShadow">
<mat-card-content class="p-y-24">
<img src="{{ friendcard.imgSrc }}" alt="user" width="80" class="rounded-circle" />
<mat-card-title class="m-t-16">{{ friendcard.title }}</mat-card-title>
<div class="d-flex align-items-center">
<div class="avatar-group m-r-8">
<img src="/assets/images/profile/user-1.jpg" alt="user" class="rounded-circle" width="28" />
<img src="/assets/images/profile/user-2.jpg" alt="user" class="rounded-circle" width="28" />
<img src="/assets/images/profile/user-3.jpg" alt="user" class="rounded-circle" width="28" />
</div>
<span class="f-s-14">3 mutual friends</span>
</div>
<button mat-flat-button color="primary" class="w-100 m-t-24">
Add Friend
</button>
<button mat-stroked-button color="warn" class="w-100 m-t-8">
Remove
</button>
</mat-card-content>
</mat-card>
</div>
}
</div>
<!-- --------------------------------------------------------------------- -->
<!-- card 7 -->
<!-- --------------------------------------------------------------------- -->
<div class="row">
@for(socialcard of socialcards; track socialcard.username) {
<div class="col-sm-6 col-lg-4">
<mat-card class="cardWithShadow overflow-hidden">
<mat-card-content class="text-center p-y-24">
<img src="{{ socialcard.imgSrc }}" class="rounded-circle" width="80" />
<mat-card-title class="f-s-18 m-b-0 m-t-16">{{
socialcard.username
}}</mat-card-title>
<mat-card-subtitle class="f-s-12 f-s-14">{{
socialcard.post
}}</mat-card-subtitle>
</mat-card-content>
<div class="b-t-1 p-x-24 p-y-8 d-flex justify-content-center bg-light-primary">
<button mat-icon-button class="d-flex justify-content-center">
<i-tabler name="brand-facebook" class="icon-18 d-flex text-primary"></i-tabler>
</button>
<button mat-icon-button class="d-flex justify-content-center">
<i-tabler name="brand-instagram" class="icon-18 d-flex text-error"></i-tabler>
</button>
<button mat-icon-button class="d-flex justify-content-center">
<i-tabler name="brand-github" class="icon-18 d-flex text-success"></i-tabler>
</button>
<button mat-icon-button class="d-flex justify-content-center">
<i-tabler name="brand-twitter" class="icon-18 d-flex text-secondary"></i-tabler>
</button>
</div>
</mat-card>
</div>
}
</div>
<!-- --------------------------------------------------------------------- -->
<!-- card 8 -->
<!-- --------------------------------------------------------------------- -->
<div class="row">
@for(giftcard of giftcards; track giftcard.username) {
<div class="col-sm-6 col-lg-4">
<mat-card class="cardWithShadow">
<mat-card-content class="p-y-24">
<div class="d-flex justify-content-between align-items-center">
<mat-card-title class="f-s-16">{{
giftcard.username
}}</mat-card-title>
<i-tabler name="gift" class="icon-18 text-primary"></i-tabler>
</div>
<img src="{{ giftcard.imgSrc }}" alt="user" class="rounded w-100 m-t-8" />
<button mat-flat-button color="primary" class="w-100 m-t-8">
Gift to Friend ($50.00)
</button>
</mat-card-content>
</mat-card>
</div>
}
</div>
<div class="row">
<!-- column -->
<div class="col-lg-4">
<mat-card class="cardWithShadow">
<mat-card-content class="p-y-24">
<mat-card-title>Payment Gateways</mat-card-title>
<mat-card-subtitle class="f-s-14 p-b-16">Platform For Income</mat-card-subtitle>
@for(stat of stats; track stat.title) {
<div class="m-t-32">
<div class="d-flex align-items-center m-b-24">
<span class="text-{{ stat.color }} bg-light-{{
stat.color
}} rounded icon-40 d-flex align-items-center justify-content-center">
<img [src]="stat.img" alt="icon" />
</span>
<div class="m-l-16 m-r-auto">
<h6 class="f-s-16 f-w-600">{{ stat.title }}</h6>
<span class="f-s-14">{{ stat.subtitle }}</span>
</div>
<span class="f-w-600 f-s-14"> +${{ stat.percent }} </span>
</div>
</div>
}
<button mat-stroked-button color="primary" class="w-100 m-t-8">
View all Transctions
</button>
</mat-card-content>
</mat-card>
</div>
<!-- column -->
<div class="col-lg-4">
<mat-card class="cardWithShadow">
<mat-card-content class="p-t-24">
<mat-card-title>Upcoming Activity</mat-card-title>
<mat-card-subtitle class="f-s-14 p-b-16">In New year</mat-card-subtitle>
@for(activity of activities; track activity.title) {
<div>
<div class="d-flex align-items-center p-y-16">
<span class="text-{{ activity.color }} bg-light-{{
activity.color
}} rounded icon-40 d-flex align-items-center justify-content-center">
<i-tabler name="{{ activity.icon }}" class="icon-18 d-flex"></i-tabler>
</span>
<div class="m-l-16 m-r-auto">
<h6 class="f-s-16 f-w-600">{{ activity.title }}</h6>
<span class="f-s-14">{{ activity.subtitle }}</span>
</div>
<span class="f-s-14">{{ activity.time }} </span>
</div>
</div>
}
</mat-card-content>
</mat-card>
</div>
<!-- column -->
<div class="col-lg-4">
<mat-card class="cardWithShadow">
<mat-card-content class="p-y-24">
<mat-card-title>Recent Transactions</mat-card-title>
<div class="timeline m-t-24">
@for(stat of stats2; track stat.subtext) {
<div class="timeline-item d-flex overflow-hidden">
<div class="time text-right f-s-14">{{ stat.time }}</div>
<div class="point d-flex align-items-center">
<span class="timeline-badge border-{{ stat.color }} m-y-8"></span>
<span class="timline-border d-block"></span>
</div>
<div class="desc">
@if(stat.subtext) {
<span class="f-s-14 lh-20">{{ stat.subtext }}</span>
}
@if(stat.title) {
<span class="f-s-14 lh-20 f-w-600 d-block">{{
stat.title
}}</span>
}
@if(stat.link) {
<a href="#" class="text-primary text-decoration-none f-s-14">#ML-3467</a>
}
</div>
</div>
}
</div>
</mat-card-content>
</mat-card>
</div>
</div>

View File

@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { FrontEndService } from './front-end.service';
describe('FrontEndService', () => {
let service: FrontEndService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(FrontEndService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View File

@@ -0,0 +1,21 @@
import { Injectable, signal } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class FrontEndService {
private blog = signal<any>(null);
constructor() { }
setBlog(blogData: any) {
this.blog.set(blogData);
}
getBlog() {
return this.blog;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 39 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 33 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

View File

@@ -0,0 +1,31 @@
<svg width="81" height="34" viewBox="0 0 81 34" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_21817_22125)">
<path d="M7.73608 9.75H10.4861L9.11108 6.25L7.73608 9.75Z" fill="#2FABF7"/>
<path d="M41.8611 6.75C41.6111 6.625 41.2361 6.625 40.8611 6.625H38.3611V8.625H40.8611C41.2361 8.625 41.6111 8.625 41.8611 8.5C42.1111 8.375 42.2361 8 42.2361 7.625C42.3611 7.125 42.1111 6.875 41.8611 6.75Z" fill="#228FE0"/>
<path d="M68.6111 3V4.5L67.8611 3H61.9861V4.5L61.2361 3H53.2361C51.8611 3 50.7361 3.25 49.7361 3.75V3H44.1111V3.75C43.4861 3.25 42.7361 3 41.7361 3H21.6111L20.2361 6.125L18.8611 3H12.4861V4.5L11.7361 3H6.36108L3.86108 8.875L0.986084 15.375H3.86108H7.36108L8.11108 13.375H9.86108L10.6111 15.375H17.8611V13.875L18.4861 15.375H22.1111L22.7361 13.875V15.375H40.1111V12.125H40.3611C40.6111 12.125 40.6111 12.125 40.6111 12.5V15.25H49.6111V14.5C50.3611 14.875 51.4861 15.25 52.9861 15.25H56.7361L57.4861 13.25H59.2361L59.9861 15.25H67.2361V13.375L68.3611 15.25H74.2361V3H68.6111ZM26.3611 13.5H24.2361V6.625L21.2361 13.5H19.3611L16.3611 6.625V13.5H12.1111L11.2361 11.625H6.98608L6.23608 13.625H3.86108L7.61108 4.75H10.7361L14.2361 13.125V4.75H17.6111L20.3611 10.75L22.8611 4.75H26.3611V13.5ZM34.8611 6.625H29.9861V8.25H34.7361V10H29.9861V11.75H34.8611V13.625H27.8611V4.75H34.8611V6.625ZM44.2361 10.25C44.4861 10.75 44.6111 11.125 44.6111 11.875V13.625H42.4861V12.5C42.4861 12 42.4861 11.25 42.1111 10.75C41.7361 10.375 41.3611 10.375 40.6111 10.375H38.3611V13.625H36.2361V4.75H40.9861C42.1111 4.75 42.8611 4.75 43.4861 5.125C44.1111 5.5 44.4861 6.125 44.4861 7.125C44.4861 8.5 43.6111 9.25 42.9861 9.5C43.6111 9.625 43.9861 10 44.2361 10.25ZM47.9861 13.5H45.8611V4.625H47.9861V13.5ZM72.6111 13.5H69.6111L65.6111 6.875V13.5H61.3611L60.6111 11.625H56.2361L55.4861 13.625H53.1111C52.1111 13.625 50.8611 13.375 50.1111 12.625C49.3611 11.875 48.9861 10.875 48.9861 9.25C48.9861 8 49.2361 6.75 50.1111 5.75C50.7361 5 51.8611 4.75 53.2361 4.75H55.2361V6.625H53.2361C52.4861 6.625 52.1111 6.75 51.6111 7.125C51.2361 7.5 50.9861 8.25 50.9861 9.125C50.9861 10.125 51.1111 10.75 51.6111 11.25C51.9861 11.625 52.4861 11.75 53.1111 11.75H53.9861L56.8611 4.875H59.9861L63.4861 13.25V4.875H66.6111L70.2361 11V4.875H72.3611V13.5H72.6111Z" fill="#0571C1"/>
<path d="M56.9861 9.75H59.8611L58.4861 6.25L56.9861 9.75Z" fill="#228FE0"/>
<path d="M35.7361 27.75V20.625L32.4861 24.125L35.7361 27.75Z" fill="#228FE0"/>
<path d="M22.3611 21.5V23.125H26.9861V24.875H22.3611V26.75H27.4861L29.8611 24.125L27.6111 21.5H22.3611Z" fill="#2FABF7"/>
<path d="M40.4861 21.5H37.8611V23.75H40.6111C41.3611 23.75 41.8611 23.375 41.8611 22.625C41.7361 21.875 41.2361 21.5 40.4861 21.5Z" fill="#228FE0"/>
<path d="M79.1111 23.625V18H77.6111H73.8611C72.7361 18 71.8611 18.25 71.2361 18.75V18H65.4861C64.6111 18 63.4861 18.25 62.9861 18.75V18H52.8611V18.75C52.1111 18.125 50.7361 18 50.1111 18H43.3611V18.75C42.7361 18.125 41.2361 18 40.4861 18H32.9861L31.2361 19.875L29.6111 18H18.3611V30.25H29.3611L31.1111 28.375L32.7361 30.25H39.4861V27.375H40.3611C41.2361 27.375 42.3611 27.375 43.2361 27V30.375H48.8611V27.125H49.1111C49.4861 27.125 49.4861 27.125 49.4861 27.5V30.375H66.4861C67.6111 30.375 68.7361 30.125 69.3611 29.625V30.375H74.7361C75.8611 30.375 76.9861 30.25 77.7361 29.75C78.9861 29 79.7361 27.625 79.7361 26C79.7361 25.125 79.4861 24.25 79.1111 23.625ZM40.3611 25.625H37.8611V28.625H33.8611L31.3611 25.75L28.7361 28.625H20.4861V19.75H28.8611L31.3611 22.625L33.9861 19.75H40.6111C42.2361 19.75 44.1111 20.25 44.1111 22.625C43.9861 25.125 42.2361 25.625 40.3611 25.625ZM52.8611 25.125C53.1111 25.5 53.2361 26 53.2361 26.75V28.5H51.1111V27.375C51.1111 26.875 51.1111 26 50.7361 25.625C50.4861 25.25 49.9861 25.25 49.2361 25.25H46.9861V28.5H44.8611V19.625H49.6111C50.6111 19.625 51.4861 19.625 52.1111 20C52.7361 20.375 53.2361 21 53.2361 22C53.2361 23.375 52.3611 24.125 51.7361 24.375C52.3611 24.625 52.7361 24.875 52.8611 25.125ZM61.4861 21.5H56.6111V23.125H61.3611V24.875H56.6111V26.625H61.4861V28.5H54.4861V19.625H61.4861V21.5ZM66.7361 28.5H62.7361V26.625H66.7361C67.1111 26.625 67.3611 26.625 67.6111 26.375C67.7361 26.25 67.8611 26 67.8611 25.75C67.8611 25.5 67.7361 25.25 67.6111 25.125C67.4861 25 67.2361 24.875 66.8611 24.875C64.8611 24.75 62.4861 24.875 62.4861 22.125C62.4861 20.875 63.2361 19.5 65.4861 19.5H69.6111V21.625H65.7361C65.3611 21.625 65.1111 21.625 64.8611 21.75C64.6111 21.875 64.6111 22.125 64.6111 22.375C64.6111 22.75 64.8611 22.875 65.1111 23C65.3611 23.125 65.6111 23.125 65.8611 23.125H66.9861C68.1111 23.125 68.8611 23.375 69.3611 23.875C69.7361 24.25 69.9861 24.875 69.9861 25.75C69.9861 27.625 68.8611 28.5 66.7361 28.5ZM77.4861 27.625C76.9861 28.125 76.1111 28.5 74.8611 28.5H70.8611V26.625H74.8611C75.2361 26.625 75.4861 26.625 75.7361 26.375C75.8611 26.25 75.9861 26 75.9861 25.75C75.9861 25.5 75.8611 25.25 75.7361 25.125C75.6111 25 75.3611 24.875 74.9861 24.875C72.9861 24.75 70.6111 24.875 70.6111 22.125C70.6111 20.875 71.3611 19.5 73.6111 19.5H77.7361V21.625H73.9861C73.6111 21.625 73.3611 21.625 73.1111 21.75C72.8611 21.875 72.8611 22.125 72.8611 22.375C72.8611 22.75 72.9861 22.875 73.3611 23C73.6111 23.125 73.8611 23.125 74.1111 23.125H75.2361C76.3611 23.125 77.1111 23.375 77.6111 23.875C77.7361 23.875 77.7361 24 77.7361 24C78.1111 24.5 78.2361 25.125 78.2361 25.75C78.2361 26.5 77.9861 27.125 77.4861 27.625Z" fill="#0571C1"/>
<path d="M50.6111 21.75C50.3611 21.625 49.9861 21.625 49.6111 21.625H47.1111V23.625H49.6111C49.9861 23.625 50.3611 23.625 50.6111 23.5C50.8611 23.375 50.9861 23 50.9861 22.625C51.1111 22.125 50.8611 21.875 50.6111 21.75Z" fill="#228FE0"/>
<path d="M41.8611 6.75C41.6111 6.625 41.2361 6.625 40.8611 6.625H38.3611V8.625H40.8611C41.2361 8.625 41.6111 8.625 41.8611 8.5C42.1111 8.375 42.2361 8 42.2361 7.625C42.3611 7.125 42.1111 6.875 41.8611 6.75Z" fill="#228FE0"/>
<path d="M56.9861 9.75H59.8611L58.4861 6.25L56.9861 9.75Z" fill="#228FE0"/>
<path d="M35.7361 27.75V20.625L32.4861 24.125L35.7361 27.75Z" fill="#228FE0"/>
<path d="M40.4861 21.5H37.8611V23.75H40.6111C41.3611 23.75 41.8611 23.375 41.8611 22.625C41.7361 21.875 41.2361 21.5 40.4861 21.5Z" fill="#228FE0"/>
<path d="M50.6111 21.75C50.3611 21.625 49.9861 21.625 49.6111 21.625H47.1111V23.625H49.6111C49.9861 23.625 50.3611 23.625 50.6111 23.5C50.8611 23.375 50.9861 23 50.9861 22.625C51.1111 22.125 50.8611 21.875 50.6111 21.75Z" fill="#228FE0"/>
<path d="M39.6111 28.25L37.8611 26.375V28.5H33.7361L31.2361 25.625L28.4861 28.5H20.2361V19.75H28.6111L31.2361 22.625L32.4861 21.125L29.3611 18H18.3611V30.25H29.3611L31.2361 28.375L32.8611 30.25H39.6111V28.25Z" fill="#2FABF7"/>
<path d="M26.6111 15.25L24.9861 13.5H24.2361V12.75L22.3611 10.875L21.1111 13.5H19.3611L16.3611 6.625V13.5H12.1111L11.2361 11.625H6.98608L6.11108 13.5H3.86108L7.61108 4.75H10.7361L14.2361 13.125V4.75H16.1111L14.3611 3H12.4861V4.5L11.8611 3H6.36108L3.86108 8.875L0.986084 15.25H3.86108H7.48608L8.23608 13.375H9.98608L10.8611 15.25H17.8611V13.75L18.4861 15.25H22.1111L22.7361 13.75V15.25H26.6111Z" fill="#2FABF7"/>
<path d="M20.8611 9.5L18.8611 7.5L20.3611 10.75L20.8611 9.5Z" fill="#2FABF7"/>
<path d="M77.7361 29.625C78.8611 28.875 79.6111 27.625 79.7361 26.25L77.9861 24.5C78.1111 24.875 78.2361 25.25 78.2361 25.75C78.2361 26.5 77.9861 27.125 77.4861 27.625C76.9861 28.125 76.1111 28.5 74.8611 28.5H70.8611V26.625H74.8611C75.2361 26.625 75.4861 26.625 75.7361 26.375C75.8611 26.25 75.9861 26 75.9861 25.75C75.9861 25.5 75.8611 25.25 75.7361 25.125C75.6111 25 75.3611 24.875 74.9861 24.875C72.9861 24.75 70.6111 24.875 70.6111 22.125C70.6111 20.875 71.3611 19.75 73.2361 19.5L71.8611 18.125C71.6111 18.25 71.4861 18.375 71.3611 18.375V17.625H65.6111C64.7361 17.625 63.6111 17.875 63.1111 18.375V17.625H52.8611V18.375C52.1111 17.75 50.7361 17.625 50.1111 17.625H43.3611V18.375C42.7361 17.75 41.2361 17.625 40.4861 17.625H32.9861L31.2361 19.5L29.6111 17.625H28.2361L31.9861 21.375L33.8611 19.375H40.4861C42.1111 19.375 43.9861 19.875 43.9861 22.25C43.9861 24.75 42.2361 25.25 40.3611 25.25H37.8611V27.125L39.7361 29V27.125H40.3611C41.2361 27.125 42.3611 27.125 43.2361 26.75V30.125H48.8611V26.875H49.1111C49.4861 26.875 49.4861 26.875 49.4861 27.25V30.125H66.4861C67.6111 30.125 68.7361 29.875 69.3611 29.375V30.125H74.7361C75.7361 30.25 76.8611 30.125 77.7361 29.625ZM52.8611 25.125C53.1111 25.5 53.2361 26 53.2361 26.75V28.5H51.1111V27.375C51.1111 26.875 51.1111 26 50.7361 25.625C50.4861 25.25 49.9861 25.25 49.2361 25.25H46.9861V28.5H44.8611V19.625H49.6111C50.6111 19.625 51.4861 19.625 52.1111 20C52.7361 20.375 53.2361 21 53.2361 22C53.2361 23.375 52.3611 24.125 51.7361 24.375C52.3611 24.625 52.7361 24.875 52.8611 25.125ZM61.4861 21.5H56.6111V23.125H61.3611V24.875H56.6111V26.625H61.4861V28.5H54.4861V19.625H61.4861V21.5ZM66.7361 28.5H62.7361V26.625H66.7361C67.1111 26.625 67.3611 26.625 67.6111 26.375C67.7361 26.25 67.8611 26 67.8611 25.75C67.8611 25.5 67.7361 25.25 67.6111 25.125C67.4861 25 67.2361 24.875 66.8611 24.875C64.8611 24.75 62.4861 24.875 62.4861 22.125C62.4861 20.875 63.2361 19.5 65.4861 19.5H69.6111V21.625H65.7361C65.3611 21.625 65.1111 21.625 64.8611 21.75C64.6111 21.875 64.6111 22.125 64.6111 22.375C64.6111 22.75 64.8611 22.875 65.1111 23C65.3611 23.125 65.6111 23.125 65.8611 23.125H66.9861C68.1111 23.125 68.8611 23.375 69.3611 23.875C69.7361 24.25 69.9861 24.875 69.9861 25.75C69.9861 27.625 68.8611 28.5 66.7361 28.5Z" fill="#228FE0"/>
<path d="M72.7361 22.375C72.7361 22.75 72.8611 22.875 73.2361 23C73.4861 23.125 73.7361 23.125 73.9861 23.125H75.1111C75.8611 23.125 76.3611 23.25 76.8611 23.5L74.9861 21.625H73.8611C73.4861 21.625 73.2361 21.625 72.9861 21.75C72.8611 21.875 72.7361 22.125 72.7361 22.375Z" fill="#228FE0"/>
<path d="M68.3611 14.875L68.6111 15.25H68.7361L68.3611 14.875Z" fill="#228FE0"/>
<path d="M61.4861 8L63.6111 13.125V10.125L61.4861 8Z" fill="#228FE0"/>
<path d="M40.1111 12.125H40.3611C40.6111 12.125 40.6111 12.125 40.6111 12.5V15.25H49.6111V14.5C50.3611 14.875 51.4861 15.25 52.9861 15.25H56.7361L57.4861 13.25H59.2361L59.9861 15.25H67.2361V14L65.4861 12.25V13.625H61.2361L60.6111 11.625H56.2361L55.4861 13.625H53.1111C52.1111 13.625 50.8611 13.375 50.1111 12.625C49.3611 11.875 48.9861 10.875 48.9861 9.25C48.9861 8 49.2361 6.75 50.1111 5.75C50.7361 5 51.8611 4.75 53.2361 4.75H55.2361V6.625H53.2361C52.4861 6.625 52.1111 6.75 51.6111 7.125C51.2361 7.5 50.9861 8.25 50.9861 9.125C50.9861 10.125 51.1111 10.75 51.6111 11.25C51.9861 11.625 52.4861 11.75 53.1111 11.75H53.9861L56.8611 4.875H58.1111L56.3611 3.125H53.1111C51.7361 3.125 50.6111 3.375 49.6111 3.875V3.125H44.1111V3.875C43.4861 3.375 42.7361 3.125 41.7361 3.125H21.6111L20.2361 6.25L18.8611 3.125H13.3611L15.1111 4.875H17.6111L19.7361 9.5L20.4861 10.25L22.7361 4.75H26.2361V13.625H24.1111V6.75L21.9861 11.75L25.6111 15.375H39.9861L40.1111 12.125ZM45.8611 4.75H47.9861V13.625H45.8611V4.75ZM34.8611 6.625H29.9861V8.25H34.7361V10H29.9861V11.75H34.8611V13.625H27.8611V4.75H34.8611V6.625ZM38.3611 13.5H36.2361V4.625H40.9861C42.1111 4.625 42.8611 4.625 43.4861 5C44.1111 5.375 44.4861 6 44.4861 7C44.4861 8.375 43.6111 9.125 42.9861 9.375C43.4861 9.5 43.8611 9.875 43.9861 10.125C44.2361 10.625 44.3611 11 44.3611 11.75V13.5H42.2361V12.375C42.2361 11.875 42.2361 11.125 41.8611 10.625C41.7361 10.375 41.3611 10.375 40.6111 10.375H38.3611V13.5Z" fill="#228FE0"/>
</g>
<defs>
<clipPath id="clip0_21817_22125">
<rect width="80" height="34" fill="white" transform="translate(0.193115)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

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