8 Commits

Author SHA1 Message Date
Marek Lesko
e3c22289cf fix: Minor fixes for CI/CD process 2025-07-15 19:25:38 +00:00
Marek Lesko
d9b58b0502 fix: Updated CI/CD configuration 2025-07-15 19:25:38 +00:00
Marek Lesko
6a1dc75b3b fix: Update .gitlab-ci.yml file 2025-07-15 18:15:12 +00:00
Marek Lesko
57b35ae431 fix: Update .gitlab-ci.yml file 2025-07-15 18:13:05 +00:00
Marek Lesko
4e25c0179e Merge branch 'dev' into 'main'
Dev

See merge request marek/centrum!7
2025-07-14 19:14:10 +00:00
Marek Lesko
0a0f1ea10a fix: Dev 2025-07-14 19:14:10 +00:00
Marek Lesko
2d1982d010 Merge branch 'dev' into 'main'
fix: UPDATED build configuration

See merge request marek/centrum!6
2025-07-14 19:01:31 +00:00
Marek Lesko
65d5e4b46a fix: UPDATED build configuration 2025-07-14 19:01:31 +00:00
352 changed files with 35666 additions and 3 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
.vs/

View File

@@ -4,9 +4,10 @@ stages: # Define the stages of the pipeline.
#- test #- test
- release - release
install-job: # This job runs in the build stage, which runs first. web-build: # This job runs in the build stage, which runs first.
stage: build stage: build
image: node:24 image: node:24
parallel: 2
script: script:
- cd Web - cd Web
- npm install - npm install
@@ -15,12 +16,27 @@ install-job: # This job runs in the build stage, which runs first.
paths: paths:
- Web/dist/Web/browser # The 'dist' directory will be available in the next stage. - Web/dist/Web/browser # The 'dist' directory will be available in the next stage.
api-build:
stage: build
image: mcr.microsoft.com/dotnet/sdk:8.0
parallel: 2
script:
- cd Api
- dotnet publish Api.csproj --output ./build --runtime linux-x64 --configuration Release --self-contained true
artifacts:
paths:
- Api/build
when: on_success
access: all
expire_in: 30 days
semantic-release: semantic-release:
image: node:24 image: node:24
stage: release stage: release
script: script:
- apt update && apt install zip -y - apt update && apt install zip -y
- zip -r dist.zip Web/dist/Web/browser - zip -r dist.zip Web/dist/Web/browser
- zip -r api.zip Api/build
- npm install --save-dev @semantic-release/gitlab - npm install --save-dev @semantic-release/gitlab
- npx semantic-release --debug - npx semantic-release --debug
only: only:
@@ -33,4 +49,7 @@ deploy-job: # This job runs in the deploy stage.
- deployment - deployment
script: script:
- cp -ir Web/dist/Web/browser/* /var/www/html - cp -ir Web/dist/Web/browser/* /var/www/html
- systemctl stop api.service
- cp -ir Api/build/* /var/api
- systemctl start api.service
- echo "Application successfully deployed." - echo "Application successfully deployed."

View File

@@ -11,7 +11,8 @@
"@semantic-release/gitlab" "@semantic-release/gitlab"
], ],
"assets": [ "assets": [
{ "path": "dist.zip", "label": "bundle" }, { "path": "dist.zip", "label": "Web.zip" },
{ "path": "api.zip", "label": "Api.zip" },
{ "url": "https://gitlab.lesko.me/marek/centrum/-/blob/main/README.md", "label": "README.md" } { "url": "https://gitlab.lesko.me/marek/centrum/-/blob/main/README.md", "label": "README.md" }
] ]
} }

View File

@@ -0,0 +1,5 @@
{
"version": 1,
"isRoot": true,
"tools": {}
}

30
Api/.dockerignore Normal file
View File

@@ -0,0 +1,30 @@
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
!**/.gitignore
!.git/HEAD
!.git/config
!.git/packed-refs
!.git/refs/heads/**

4
Api/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
obj/
bin/
.vs/
build/

21
Api/Api.csproj Normal file
View File

@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>aspnet-Api-50db7f4c-1c75-467a-a923-a5477d7decc4</UserSecretsId>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<DockerfileContext>.</DockerfileContext>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.18" NoWarn="NU1605" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="8.0.18" NoWarn="NU1605" />
<PackageReference Include="Microsoft.Identity.Web" Version="3.10.0" />
<PackageReference Include="Microsoft.Identity.Web.DownstreamApi" Version="3.10.0" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.22.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.3" />
</ItemGroup>
</Project>

9
Api/Api.csproj.user Normal file
View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ActiveDebugProfile>https</ActiveDebugProfile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>

6
Api/Api.http Normal file
View File

@@ -0,0 +1,6 @@
@Api_HostAddress = http://localhost:5012
GET {{Api_HostAddress}}/weatherforecast/
Accept: application/json
###

31
Api/Api.sln Normal file
View File

@@ -0,0 +1,31 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.14.36301.6
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Api", "Api.csproj", "{EC86C676-06E8-4011-A4E3-5118543F4728}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "..\Tests\Tests.csproj", "{819F3EDC-F488-4C63-89D0-4BE09CD0C485}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{EC86C676-06E8-4011-A4E3-5118543F4728}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EC86C676-06E8-4011-A4E3-5118543F4728}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EC86C676-06E8-4011-A4E3-5118543F4728}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EC86C676-06E8-4011-A4E3-5118543F4728}.Release|Any CPU.Build.0 = Release|Any CPU
{819F3EDC-F488-4C63-89D0-4BE09CD0C485}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{819F3EDC-F488-4C63-89D0-4BE09CD0C485}.Debug|Any CPU.Build.0 = Debug|Any CPU
{819F3EDC-F488-4C63-89D0-4BE09CD0C485}.Release|Any CPU.ActiveCfg = Release|Any CPU
{819F3EDC-F488-4C63-89D0-4BE09CD0C485}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A7800B0A-84E4-432A-9E11-6EF3987291FC}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,37 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Identity.Web.Resource;
namespace Api.Controllers
{
//[Authorize]
[ApiController]
[Route("[controller]")]
//[RequiredScope(RequiredScopesConfigurationKey = "AzureAd:Scopes")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
}

30
Api/Dockerfile Normal file
View File

@@ -0,0 +1,30 @@
# See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
# This stage is used when running from VS in fast mode (Default for Debug configuration)
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER $APP_UID
WORKDIR /app
EXPOSE 8080
EXPOSE 8081
# This stage is used to build the service project
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["Api.csproj", "."]
RUN dotnet restore "./Api.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "./Api.csproj" -c $BUILD_CONFIGURATION -o /app/build
# This stage is used to publish the service project to be copied to the final stage
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./Api.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
# This stage is used in production or when running from VS in regular mode (Default when not using the Debug configuration)
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Api.dll"]

45
Api/Program.cs Normal file
View File

@@ -0,0 +1,45 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Abstractions;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.Resource;
namespace Api
{
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
//builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
// .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
// if (app.Environment.IsDevelopment())
// {
app.UseSwagger();
app.UseSwaggerUI();
// }
if (!app.Environment.IsDevelopment())
{
app.UseHttpsRedirection();
}
// app.UseAuthorization();
app.MapControllers();
app.Run();
}
}
}

View File

@@ -0,0 +1,42 @@
{
"profiles": {
"https": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"dotnetRunMessages": true,
"applicationUrl": "https://localhost:7145;http://localhost:5012"
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Container (Dockerfile)": {
"commandName": "Docker",
"launchBrowser": true,
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
"environmentVariables": {
"ASPNETCORE_HTTPS_PORTS": "8081",
"ASPNETCORE_HTTP_PORTS": "8080"
},
"publishAllPorts": true,
"useSSL": true
}
},
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:60760",
"sslPort": 44315
}
}
}

13
Api/WeatherForecast.cs Normal file
View File

@@ -0,0 +1,13 @@
namespace Api
{
public class WeatherForecast
{
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string? Summary { get; set; }
}
}

View File

@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

23
Api/appsettings.json Normal file
View File

@@ -0,0 +1,23 @@
{
/*
The following identity settings need to be configured
before the project can be successfully executed.
For more info see https://aka.ms/dotnet-template-ms-identity-platform
*/
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "qualified.domain.name",
"TenantId": "22222222-2222-2222-2222-222222222222",
"ClientId": "11111111-1111-1111-11111111111111111",
"Scopes": "access_as_user",
"CallbackPath": "/signin-oidc"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

BIN
Api/core Normal file

Binary file not shown.

2
Tests/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
obj/
bin/

38
Tests/IntegrationTest1.cs Normal file
View File

@@ -0,0 +1,38 @@
namespace Tests.Tests
{
public class IntegrationTest1
{
// Instructions:
// 1. Add a project reference to the target AppHost project, e.g.:
//
// <ItemGroup>
// <ProjectReference Include="../MyAspireApp.AppHost/MyAspireApp.AppHost.csproj" />
// </ItemGroup>
//
// 2. Uncomment the following example test and update 'Projects.MyAspireApp_AppHost' to match your AppHost project:
//
// [Fact]
// public async Task GetWebResourceRootReturnsOkStatusCode()
// {
// // Arrange
// var appHost = await DistributedApplicationTestingBuilder.CreateAsync<Projects.MyAspireApp_AppHost>();
// appHost.Services.ConfigureHttpClientDefaults(clientBuilder =>
// {
// clientBuilder.AddStandardResilienceHandler();
// });
// // To output logs to the xUnit.net ITestOutputHelper, consider adding a package from https://www.nuget.org/packages?q=xunit+logging
//
// await using var app = await appHost.BuildAsync();
// var resourceNotificationService = app.Services.GetRequiredService<ResourceNotificationService>();
// await app.StartAsync();
// // Act
// var httpClient = app.CreateHttpClient("webfrontend");
// await resourceNotificationService.WaitForResourceAsync("webfrontend", KnownResourceStates.Running).WaitAsync(TimeSpan.FromSeconds(30));
// var response = await httpClient.GetAsync("/");
// // Assert
// Assert.Equal(HttpStatusCode.OK, response.StatusCode);
// }
}
}

27
Tests/Tests.csproj Normal file
View File

@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.Testing" Version="9.3.1" />
<PackageReference Include="coverlet.collector" Version="6.0.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
</ItemGroup>
<ItemGroup>
<Using Include="System.Net" />
<Using Include="Microsoft.Extensions.DependencyInjection" />
<Using Include="Aspire.Hosting.ApplicationModel" />
<Using Include="Aspire.Hosting.Testing" />
<Using Include="Xunit" />
</ItemGroup>
</Project>

View File

@@ -4,7 +4,7 @@
"scripts": { "scripts": {
"ng": "ng", "ng": "ng",
"start": "ng serve --host 0.0.0.0", "start": "ng serve --host 0.0.0.0",
"build": "ng build", "build": "ng build --configuration=production",
"watch": "ng build --watch --configuration development", "watch": "ng build --watch --configuration development",
"test": "ng test" "test": "ng test"
}, },

View File

@@ -0,0 +1,16 @@
# Editor configuration, see https://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.ts]
quote_type = single
[*.md]
max_line_length = off
trim_trailing_whitespace = false

42
Web/themes/modernize/.gitignore vendored Normal file
View File

@@ -0,0 +1,42 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# Compiled output
/dist
/tmp
/out-tsc
/bazel-out
# Node
/node_modules
npm-debug.log
yarn-error.log
# IDEs and editors
.idea/
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# Visual Studio Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# Miscellaneous
/.angular/cache
.sass-cache/
/connect.lock
/coverage
/libpeerconnection.log
testem.log
/typings
# System files
.DS_Store
Thumbs.db

View File

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

View File

@@ -0,0 +1,2 @@
# Modernize-Angular-pro
Modernize Angular Admin Dashboard

View File

@@ -0,0 +1,96 @@
{
"$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-devkit/build-angular:browser",
"options": {
"allowedCommonJsDependencies": ["apexcharts", "bezier-easing", "moment"],
"outputPath": "dist/Modernize",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": ["zone.js"],
"tsConfig": "tsconfig.app.json",
"inlineStyleLanguage": "scss",
"assets": ["src/favicon.ico", "src/assets"],
"styles": ["src/styles.scss", "src/assets/scss/style.scss"],
"scripts": []
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "12mb",
"maximumError": "12mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "12mb",
"maximumError": "12mb"
}
],
"outputHashing": "all"
},
"development": {
"buildOptimizer": false,
"optimization": false,
"vendorChunk": true,
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"buildTarget": "Modernize:build:production"
},
"hmr": {
"hmr": true
},
"development": {
"buildTarget": "Modernize:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"buildTarget": "Modernize:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular: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
}
}

View File

@@ -0,0 +1,4 @@
[[redirects]]
from = "/*"
to = "/index.html"
status = 200

13801
Web/themes/modernize/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,48 @@
{
"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": "^19.0.0",
"@angular/cdk": "^19.0.0",
"@angular/common": "^19.0.0",
"@angular/compiler": "^19.0.0",
"@angular/core": "^19.0.0",
"@angular/forms": "^19.0.0",
"@angular/material": "^19.0.0",
"@angular/platform-browser": "^19.0.0",
"@angular/platform-browser-dynamic": "^19.0.0",
"@angular/router": "^19.0.0",
"@ngx-translate/core": "^14.0.0",
"@ngx-translate/http-loader": "^7.0.0",
"angular-tabler-icons": "^2.7.0",
"apexcharts": "^3.49.0",
"ng-apexcharts": "1.7.6",
"ngx-scrollbar": "^11.0.0",
"rxjs": "~7.5.0",
"sass": "1.81.0",
"tslib": "^2.3.0",
"zone.js": "~0.15.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "^19.0.1",
"@angular/cli": "~19.0.1",
"@angular/compiler-cli": "^19.0.0",
"@types/date-fns": "^2.6.0",
"@types/jasmine": "~4.3.0",
"jasmine-core": "~4.5.0",
"karma": "~6.4.0",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage": "~2.2.0",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.0.0",
"typescript": "~5.6.3"
}
}

View File

@@ -0,0 +1 @@
<router-outlet></router-outlet>

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 'Angular15'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual('Angular15');
});
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelector('.content span')?.textContent).toContain('Angular15 app is running!');
});
});

View File

@@ -0,0 +1,11 @@
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
@Component({
selector: 'app-root',
imports: [RouterOutlet],
templateUrl: './app.component.html'
})
export class AppComponent {
title = 'Modernize Angular Admin Template';
}

View File

@@ -0,0 +1,55 @@
import {
ApplicationConfig,
provideZoneChangeDetection,
importProvidersFrom,
} from '@angular/core';
import {
HttpClient,
provideHttpClient,
withInterceptorsFromDi,
} from '@angular/common/http';
import { routes } from './app.routes';
import {
provideRouter,
withComponentInputBinding,
withInMemoryScrolling,
} from '@angular/router';
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
import { provideClientHydration } from '@angular/platform-browser';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
// icons
import { TablerIconsModule } from 'angular-tabler-icons';
import * as TablerIcons from 'angular-tabler-icons/icons';
// perfect scrollbar
import { NgScrollbarModule } from 'ngx-scrollbar';
//Import all material modules
import { MaterialModule } from './material.module';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
export const appConfig: ApplicationConfig = {
providers: [
provideZoneChangeDetection({ eventCoalescing: true }),
provideRouter(
routes,
withInMemoryScrolling({
scrollPositionRestoration: 'enabled',
anchorScrolling: 'enabled',
}),
withComponentInputBinding()
),
provideHttpClient(withInterceptorsFromDi()),
provideClientHydration(),
provideAnimationsAsync(),
importProvidersFrom(
FormsModule,
ReactiveFormsModule,
MaterialModule,
TablerIconsModule.pick(TablerIcons),
NgScrollbarModule,
),
],
};

View File

@@ -0,0 +1,51 @@
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: '/dashboard',
pathMatch: 'full',
},
{
path: 'dashboard',
loadChildren: () =>
import('./pages/pages.routes').then((m) => m.PagesRoutes),
},
{
path: 'ui-components',
loadChildren: () =>
import('./pages/ui-components/ui-components.routes').then(
(m) => m.UiComponentsRoutes
),
},
{
path: 'extra',
loadChildren: () =>
import('./pages/extra/extra.routes').then((m) => m.ExtraRoutes),
},
],
},
{
path: '',
component: BlankComponent,
children: [
{
path: 'authentication',
loadChildren: () =>
import('./pages/authentication/authentication.routes').then(
(m) => m.AuthenticationRoutes
),
},
],
},
{
path: '**',
redirectTo: 'authentication/error',
},
];

View File

@@ -0,0 +1,32 @@
<div class="row">
@for(productcard of productcards; track productcards) {
<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 cart-btn bg-primary text-white d-block" matTooltip="Add to Cart">
<i-tabler name="basket" class="icon-16"></i-tabler>
</button>
<mat-card-title class="mat-headline-2 f-s-16 m-b-4">{{
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-w-600 f-s-16">${{ 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>

View File

@@ -0,0 +1,53 @@
import { Component } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { TablerIconsModule } from 'angular-tabler-icons';
// ecommerce card
interface productCards {
id: number;
imgSrc: string;
title: string;
price: string;
rprice: string;
}
@Component({
selector: 'app-blog-card',
imports: [MatCardModule, TablerIconsModule, MatButtonModule],
templateUrl: './blog-card.component.html',
})
export class AppBlogCardsComponent {
constructor() { }
productcards: productCards[] = [
{
id: 1,
imgSrc: '/assets/images/products/s4.jpg',
title: 'Boat Headphone',
price: '285',
rprice: '375',
},
{
id: 2,
imgSrc: '/assets/images/products/s5.jpg',
title: 'MacBook Air Pro',
price: '285',
rprice: '375',
},
{
id: 3,
imgSrc: '/assets/images/products/s7.jpg',
title: 'Red Valvet Dress',
price: '285',
rprice: '375',
},
{
id: 4,
imgSrc: '/assets/images/products/s11.jpg',
title: 'Cute Soft Teddybear',
price: '285',
rprice: '375',
},
];
}

View File

@@ -0,0 +1,24 @@
<mat-card class="cardWithShadow overflow-hidden">
<mat-card-content class="p-b-0">
<div class="d-flex align-items-center m-b-8">
<mat-card-title>Monthly Earnings</mat-card-title>
<div class="m-l-auto">
<button mat-fab class="icon-48 bg-secondary ">
<i-tabler name="currency-dollar" class="text-white d-flex"></i-tabler>
</button>
</div>
</div>
<h4 class="f-s-24 m-b-6">$6,820</h4>
<div class="d-flex align-items-center m-t-16">
<button mat-mini-fab class="bg-light-error text-error shadow-none icon-27 p-0 d-flex align-items-center justify-content-center">
<i-tabler name="arrow-down-right" class="icon-20 d-flex align-items-center"></i-tabler>
</button>
<div class="f-s-14 f-w-600 m-l-12">+9%</div>
<div class="f-s-14 m-l-4">last year</div>
</div>
</mat-card-content>
<apx-chart [series]="monthlyChart.series" [dataLabels]="monthlyChart.dataLabels" [chart]="monthlyChart.chart"
[legend]="monthlyChart.legend" [colors]="monthlyChart.colors" [stroke]="monthlyChart.stroke"
[tooltip]="monthlyChart.tooltip" [plotOptions]="monthlyChart.plotOptions"
[responsive]="monthlyChart.responsive"></apx-chart>
</mat-card>

View File

@@ -0,0 +1,81 @@
import { Component, ViewChild } from '@angular/core';
import {
ApexChart,
ChartComponent,
ApexDataLabels,
ApexLegend,
ApexStroke,
ApexTooltip,
ApexAxisChartSeries,
ApexPlotOptions,
ApexResponsive,
NgApexchartsModule,
} from 'ng-apexcharts';
import { TablerIconsModule } from 'angular-tabler-icons';
import { MaterialModule } from 'src/app/material.module';
export interface monthlyChart {
series: ApexAxisChartSeries;
chart: ApexChart;
dataLabels: ApexDataLabels;
plotOptions: ApexPlotOptions;
tooltip: ApexTooltip;
stroke: ApexStroke;
legend: ApexLegend;
responsive: ApexResponsive;
}
@Component({
selector: 'app-monthly-earnings',
imports: [NgApexchartsModule, MaterialModule, TablerIconsModule],
templateUrl: './monthly-earnings.component.html',
})
export class AppMonthlyEarningsComponent {
@ViewChild('chart') chart: ChartComponent = Object.create(null);
public monthlyChart!: Partial<monthlyChart> | any;
constructor() {
this.monthlyChart = {
series: [
{
name: '',
color: '#49BEFF',
data: [25, 66, 20, 40, 12, 58, 20],
},
],
chart: {
type: 'area',
fontFamily: "'Plus Jakarta Sans', sans-serif;",
foreColor: '#adb0bb',
toolbar: {
show: false,
},
height: 85,
sparkline: {
enabled: true,
},
group: 'sparklines',
},
stroke: {
curve: 'smooth',
width: 2,
},
fill: {
colors: ['#E8F7FF'],
type: 'solid',
opacity: 0.05,
},
markers: {
size: 0,
},
tooltip: {
theme: 'dark',
x: {
show: false,
},
},
};
}
}

View File

@@ -0,0 +1,98 @@
<mat-card class="cardWithShadow">
<mat-card-content>
<div class="d-flex">
<div class="m-r-auto">
<mat-card-title>Top Projects</mat-card-title>
<mat-card-subtitle>Best Products</mat-card-subtitle>
</div>
<mat-form-field class="theme-select" appearance="outline">
<mat-select value="mar">
@for(month of months; track month.value) {
<mat-option [value]="month.value">
{{ month.viewValue }}
</mat-option>
}
</mat-select>
</mat-form-field>
</div>
<div class="table-responsive">
<table mat-table [dataSource]="dataSource" class="w-100">
<!-- Position Column -->
<ng-container matColumnDef="product">
<th mat-header-cell *matHeaderCellDef class="f-w-600 f-s-14 p-l-0">
Product
</th>
<td mat-cell *matCellDef="let element" class="p-l-0">
<div class="d-flex align-items-center">
<img [src]="element.imagePath" alt="users" width="48" class="rounded" />
<div class="m-l-16">
<h6 class="f-s-14 f-w-600">
{{ element.pname }}
</h6>
<span class=" f-s-12">
{{ element.category }}
</span>
</div>
</div>
</td>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="progress">
<th mat-header-cell *matHeaderCellDef class="f-w-600 f-s-14">
Progress
</th>
<td mat-cell *matCellDef="let element">
{{ element.progress }}%
</td>
</ng-container>
<!-- Weight Column -->
<ng-container matColumnDef="status">
<th mat-header-cell *matHeaderCellDef class="f-w-600 f-s-14">
Status
</th>
<td mat-cell *matCellDef="let element">
@if(element.status == 'low') {
<span class="bg-light-success text-success rounded f-w-600 p-6 p-y-4 f-s-12">
{{ element.status | titlecase }}
</span>
}
@if(element.status == 'medium') {
<span class="bg-light-warning text-warning rounded f-w-600 p-6 p-y-4 f-s-12">
{{ element.status | titlecase }}
</span>
}
@if(element.status == 'high') {
<span class="bg-light-primary text-primary rounded f-w-600 p-6 p-y-4 f-s-12">
{{ element.status | titlecase }}
</span>
}
@if(element.status == 'critical') {
<span class="bg-light-error text-error rounded f-w-600 p-6 p-y-4 f-s-12">
{{ element.status | titlecase }}
</span>
}
</td>
</ng-container>
<!-- Symbol Column -->
<ng-container matColumnDef="sales">
<th mat-header-cell *matHeaderCellDef class="f-w-600 f-s-14">
Sales
</th>
<td mat-cell *matCellDef="let element">
${{ element.sales }}k
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>
</div>
</mat-card-content>
</mat-card>

View File

@@ -0,0 +1,80 @@
import { Component } from '@angular/core';
import { NgApexchartsModule } from 'ng-apexcharts';
import { TablerIconsModule } from 'angular-tabler-icons';
import { CommonModule } from '@angular/common';
import { MaterialModule } from 'src/app/material.module';
export interface performanceData {
id: number;
imagePath: string;
pname: string;
category: string;
progress: number;
sales: number;
status: string;
}
const ELEMENT_DATA: performanceData[] = [
{
id: 1,
imagePath: 'assets/images/products/s6.jpg',
pname: 'Gaming Console',
category: 'Electronics',
progress: 78.5,
sales: 3.9,
status: 'low',
},
{
id: 2,
imagePath: 'assets/images/products/s9.jpg',
pname: 'Leather Purse',
category: 'Fashion',
progress: 58.6,
sales: 3.5,
status: 'medium',
},
{
id: 3,
imagePath: 'assets/images/products/s7.jpg',
pname: 'Red Velvate Dress',
category: 'Womens Fashion',
progress: 25,
sales: 3.8,
status: 'high',
},
{
id: 4,
imagePath: 'assets/images/products/s4.jpg',
pname: 'Headphone Boat',
category: 'Electronics',
progress: 96.3,
sales: 3.54,
status: 'critical',
},
];
interface month {
value: string;
viewValue: string;
}
@Component({
selector: 'app-product-performance',
imports: [
NgApexchartsModule,
MaterialModule,
TablerIconsModule,
CommonModule,
],
templateUrl: './product-performance.component.html',
})
export class AppProductPerformanceComponent {
displayedColumns: string[] = ['product', 'progress', 'status', 'sales'];
dataSource = ELEMENT_DATA;
months: month[] = [
{ value: 'mar', viewValue: 'March 2025' },
{ value: 'apr', viewValue: 'April 2025' },
{ value: 'june', viewValue: 'June 2025' },
];
}

View File

@@ -0,0 +1,33 @@
<mat-card class="cardWithShadow">
<mat-card-content>
<mat-card-title>Recent Transactions</mat-card-title>
<div class="timeline m-t-24">
@for(stat of stats; track stat.title) {
<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>

View File

@@ -0,0 +1,62 @@
import { Component } from '@angular/core';
import { NgApexchartsModule } from 'ng-apexcharts';
import { MaterialModule } from 'src/app/material.module';
interface stats {
id: number;
time: string;
color: string;
title?: string;
subtext?: string;
link?: string;
}
@Component({
selector: 'app-recent-transactions',
imports: [NgApexchartsModule, MaterialModule],
templateUrl: './recent-transactions.component.html',
})
export class AppRecentTransactionsComponent {
stats: stats[] = [
{
id: 1,
time: '09.30 am',
color: 'primary',
subtext: 'Payment received from John Doe of $385.90',
},
{
id: 2,
time: '10.30 am',
color: 'accent',
title: 'New sale recorded',
link: '#ML-3467',
},
{
id: 3,
time: '12.30 pm',
color: 'success',
subtext: 'Payment was made of $64.95 to Michael',
},
{
id: 4,
time: '12.30 pm',
color: 'warning',
title: 'New sale recorded',
link: '#ML-3467',
},
{
id: 5,
time: '12.30 pm',
color: 'error',
title: 'New arrival recorded',
link: '#ML-3467',
},
{
id: 6,
time: '12.30 pm',
color: 'success',
subtext: 'Payment Done',
},
];
}

View File

@@ -0,0 +1,22 @@
<mat-card class="cardWithShadow">
<mat-card-content>
<div class="d-flex w-100">
<mat-card-title>Sales Overview</mat-card-title>
<div class="m-l-auto">
<mat-form-field class="theme-select" appearance="outline">
<mat-select value="mar">
@for(month of months; track month.viewValue ) {
<mat-option [value]="month.value">
{{ month.viewValue }}
</mat-option>
}
</mat-select>
</mat-form-field>
</div>
</div>
<apx-chart [series]="salesOverviewChart.series" [dataLabels]="salesOverviewChart.dataLabels"
[chart]="salesOverviewChart.chart" [legend]="salesOverviewChart.legend" [xaxis]="salesOverviewChart.xaxis"
[yaxis]="salesOverviewChart.yaxis" [grid]="salesOverviewChart.grid" [stroke]="salesOverviewChart.stroke"
[tooltip]="salesOverviewChart.tooltip" [plotOptions]="salesOverviewChart.plotOptions"></apx-chart>
</mat-card-content>
</mat-card>

View File

@@ -0,0 +1,153 @@
import { Component, ViewChild } from '@angular/core';
import { TablerIconsModule } from 'angular-tabler-icons';
import { MaterialModule } from 'src/app/material.module';
import {
ApexChart,
ChartComponent,
ApexDataLabels,
ApexLegend,
ApexStroke,
ApexTooltip,
ApexAxisChartSeries,
ApexXAxis,
ApexYAxis,
ApexGrid,
ApexPlotOptions,
ApexFill,
ApexMarkers,
ApexResponsive,
NgApexchartsModule,
} from 'ng-apexcharts';
import { MatButtonModule } from '@angular/material/button';
interface month {
value: string;
viewValue: string;
}
export interface salesOverviewChart {
series: ApexAxisChartSeries;
chart: ApexChart;
dataLabels: ApexDataLabels;
plotOptions: ApexPlotOptions;
yaxis: ApexYAxis;
xaxis: ApexXAxis;
fill: ApexFill;
tooltip: ApexTooltip;
stroke: ApexStroke;
legend: ApexLegend;
grid: ApexGrid;
marker: ApexMarkers;
}
@Component({
selector: 'app-sales-overview',
imports: [MaterialModule, TablerIconsModule, NgApexchartsModule, MatButtonModule],
templateUrl: './sales-overview.component.html',
})
export class AppSalesOverviewComponent {
@ViewChild('chart') chart: ChartComponent = Object.create(null);
public salesOverviewChart!: Partial<salesOverviewChart> | any;
months: month[] = [
{ value: 'mar', viewValue: 'Sep 2025' },
{ value: 'apr', viewValue: 'Oct 2025' },
{ value: 'june', viewValue: 'Nov 2025' },
];
constructor() {
// sales overview chart
this.salesOverviewChart = {
series: [
{
name: 'Eanings this month',
data: [355, 390, 300, 350, 390, 180, 355, 390],
color: '#5D87FF',
},
{
name: 'Expense this month',
data: [280, 250, 325, 215, 250, 310, 280, 250],
color: '#49BEFF',
},
],
grid: {
borderColor: 'rgba(0,0,0,0.1)',
strokeDashArray: 3,
xaxis: {
lines: {
show: false,
},
},
},
plotOptions: {
bar: { horizontal: false, columnWidth: '35%', borderRadius: [4] },
},
chart: {
type: 'bar',
height: 390,
offsetX: -15,
toolbar: { show: false },
foreColor: '#adb0bb',
fontFamily: 'inherit',
sparkline: { enabled: false },
},
dataLabels: { enabled: false },
markers: { size: 0 },
legend: { show: false },
xaxis: {
type: 'category',
categories: [
'16/08',
'17/08',
'18/08',
'19/08',
'20/08',
'21/08',
'22/08',
'23/08',
],
labels: {
style: { cssClass: 'grey--text lighten-2--text fill-color' },
},
},
yaxis: {
show: true,
min: 0,
max: 400,
tickAmount: 4,
labels: {
style: {
cssClass: 'grey--text lighten-2--text fill-color',
},
},
},
stroke: {
show: true,
width: 3,
lineCap: 'butt',
colors: ['transparent'],
},
tooltip: { theme: 'light' },
responsive: [
{
breakpoint: 600,
options: {
plotOptions: {
bar: {
borderRadius: 3,
},
},
},
},
],
};
}
}

View File

@@ -0,0 +1,34 @@
<mat-card class="cardWithShadow">
<mat-card-content>
<mat-card-title>Yearly Breakup</mat-card-title>
<div class="row m-t-24">
<div class="col-7">
<h4 class="f-s-24">$36,358</h4>
<div class="d-flex align-items-center m-t-16">
<button mat-icon-button class="bg-light-success text-success shadow-none icon-27 p-0 d-flex align-items-center justify-content-center">
<i-tabler name="arrow-up-right" class="icon-20 d-flex align-items-center"></i-tabler>
</button>
<div class="f-w-600 m-l-12 f-s-14">+9%</div>
<div class="m-l-4 f-s-14">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="m-l-12 f-s-14">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="m-l-12 f-s-14">2024</div>
</div>
</div>
</div>
<div class="col-5 d-flex align-items-start">
<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,101 @@
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
import { TablerIconsModule } from 'angular-tabler-icons';
import {
ApexChart,
ChartComponent,
ApexDataLabels,
ApexLegend,
ApexStroke,
ApexTooltip,
ApexAxisChartSeries,
ApexXAxis,
ApexYAxis,
ApexGrid,
ApexPlotOptions,
ApexFill,
ApexMarkers,
ApexResponsive,
NgApexchartsModule,
} from 'ng-apexcharts';
import { MaterialModule } from 'src/app/material.module';
export interface yearlyChart {
series: ApexAxisChartSeries;
chart: ApexChart;
dataLabels: ApexDataLabels;
plotOptions: ApexPlotOptions;
tooltip: ApexTooltip;
stroke: ApexStroke;
legend: ApexLegend;
responsive: ApexResponsive;
}
@Component({
selector: 'app-yearly-breakup',
templateUrl: './yearly-breakup.component.html',
imports: [MaterialModule, NgApexchartsModule, TablerIconsModule],
encapsulation: ViewEncapsulation.None,
})
export class AppYearlyBreakupComponent {
@ViewChild('chart') chart: ChartComponent = Object.create(null);
public yearlyChart!: Partial<yearlyChart> | any;
constructor() {
this.yearlyChart = {
color: "#adb5bd",
series: [38, 40, 25],
labels: ["2025", "2024", "2023"],
chart: {
width: 125,
type: "donut",
fontFamily: "inherit",
foreColor: "#adb0bb",
},
plotOptions: {
pie: {
startAngle: 0,
endAngle: 360,
donut: {
size: "75%",
},
},
},
stroke: {
show: false,
},
dataLabels: {
enabled: false,
},
legend: {
show: false,
},
colors: ['#5D87FF', '#ECF2FF', '#F9F9FD'],
responsive: [
{
breakpoint: 991,
options: {
chart: {
width: 120,
},
},
},
],
tooltip: {
theme: "dark",
fillSeriesColor: false,
},
};
}
}

View File

@@ -0,0 +1,11 @@
export interface AppSettings {
sidenavOpened: boolean;
sidenavCollapsed: boolean;
}
export const defaults: AppSettings = {
sidenavOpened: false,
sidenavCollapsed: false,
};

View File

@@ -0,0 +1,6 @@
<!-- ============================================================== -->
<!-- Only router without any element -->
<!-- ============================================================== -->
<mat-sidenav-container dir="ltr" class="light-theme">
<router-outlet></router-outlet>
</mat-sidenav-container>

View File

@@ -0,0 +1,23 @@
import { Component } from '@angular/core';
import { CoreService } from 'src/app/services/core.service';
import { CommonModule } from '@angular/common';
import { RouterOutlet } from '@angular/router';
import { MaterialModule } from 'src/app/material.module';
@Component({
selector: 'app-blank',
templateUrl: './blank.component.html',
styleUrls: [],
imports: [RouterOutlet, MaterialModule, CommonModule],
})
export class BlankComponent {
private htmlElement!: HTMLHtmlElement;
options = this.settings.getOptions();
constructor(private settings: CoreService) {
this.htmlElement = document.querySelector('html')!;
}
}

View File

@@ -0,0 +1,59 @@
<app-topstrip></app-topstrip>
<mat-sidenav-container class="mainWrapper blue_theme light-theme" autosize autoFocus dir="ltr">
<!-- ============================================================== -->
<!-- Vertical Sidebar -->
<!-- ============================================================== -->
<mat-sidenav #leftsidenav [mode]="isOver ? 'over' : 'side'" [opened]="!isOver"
(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()">
</app-nav-item>
}
</mat-nav-list>
</ng-scrollbar>
<div class="p-24">
<div class="bg-light-secondary d-flex align-items-center gap-4 rounded p-20 m-t-20">
<div>
<h5 class="f-s-16 f-w-600 m-b-8">
Check Pro <br> Version
</h5>
<a mat-flat-button
href="https://adminmart.com/product/modernize-angular-material-dashboard/?ref=56#product-demo-section" target="_blank"
class="d-flex justify-content-center bg-secondary">
Check
</a>
</div>
<img src="/assets/images/backgrounds/rocket.png" alt="imgae" class="side-img m-t--48 m-r--8" />
</div>
</div>
</div>
</mat-sidenav>
<!-- ============================================================== -->
<!-- Main Content -->
<!-- ============================================================== -->
<mat-sidenav-content class="contentWrapper" #content>
<!-- ============================================================== -->
<!-- VerticalHeader -->
<!-- ============================================================== -->
<app-header [showToggle]="!isOver" (toggleMobileNav)="sidenav.toggle()"></app-header>
<main class="pageWrapper maxWidth">
<!-- ============================================================== -->
<!-- Outlet -->
<!-- ============================================================== -->
<router-outlet></router-outlet>
</main>
<div class="p-16 p-b-30 text-center">
Design & Developed by <a class="text-decoration-none" href="https://adminmart.com/" target="_blank">AdminMart.com</a>
</div>
</mat-sidenav-content>
</mat-sidenav-container>

View File

@@ -0,0 +1,117 @@
import { BreakpointObserver, MediaMatcher } from '@angular/cdk/layout';
import { 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 { filter } from 'rxjs/operators';
import { NavigationEnd, Router } from '@angular/router';
import { NavService } from '../../services/nav.service';
import { RouterModule } from '@angular/router';
import { MaterialModule } from 'src/app/material.module';
import { CommonModule } from '@angular/common';
import { NgScrollbarModule } from 'ngx-scrollbar';
import { TablerIconsModule } from 'angular-tabler-icons';
import { HeaderComponent } from './header/header.component';
import { SidebarComponent } from './sidebar/sidebar.component';
import { AppNavItemComponent } from './sidebar/nav-item/nav-item.component';
import { navItems } from './sidebar/sidebar-data';
import { AppTopstripComponent } from './top-strip/topstrip.component';
const MOBILE_VIEW = 'screen and (max-width: 768px)';
const TABLET_VIEW = 'screen and (min-width: 769px) and (max-width: 1024px)';
@Component({
selector: 'app-full',
imports: [
RouterModule,
AppNavItemComponent,
MaterialModule,
CommonModule,
SidebarComponent,
NgScrollbarModule,
TablerIconsModule,
HeaderComponent,
AppTopstripComponent
],
templateUrl: './full.component.html',
styleUrls: [],
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;
}
constructor(
private settings: CoreService,
private router: Router,
private breakpointObserver: BreakpointObserver,
) {
this.htmlElement = document.querySelector('html')!;
this.layoutChangesSubscription = this.breakpointObserver
.observe([MOBILE_VIEW, TABLET_VIEW])
.subscribe((state) => {
// SidenavOpened must be reset true when layout changes
this.options.sidenavOpened = true;
this.isMobileScreen = state.breakpoints[MOBILE_VIEW];
if (this.options.sidenavCollapsed == false) {
this.options.sidenavCollapsed = state.breakpoints[TABLET_VIEW];
}
});
// Initialize project theme with options
// This is for scroll to top
this.router.events
.pipe(filter((event) => event instanceof NavigationEnd))
.subscribe((e) => {
this.content.scrollTo({ top: 0 });
});
}
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);
}
}

View File

@@ -0,0 +1,48 @@
<mat-toolbar class="topbar gap-10">
<!-- Mobile Menu -->
<button mat-icon-button (click)="toggleMobileNav.emit()" class="d-flex d-lg-none justify-content-center">
<i-tabler name="menu-2" class="icon-20 d-flex"></i-tabler>
</button>
<button mat-icon-button [matMenuTriggerFor]="menu" aria-label="Notifications">
<i-tabler class="d-flex" name="bell" matBadge="1" matBadgeColor="primary"></i-tabler>
</button>
<mat-menu #menu="matMenu">
<button mat-menu-item>Item 1</button>
<button mat-menu-item>Item 2</button>
</mat-menu>
<span class="flex-1-auto"></span>
<!-- --------------------------------------------------------------- -->
<!-- profile Dropdown -->
<!-- --------------------------------------------------------------- -->
<a mat-flat-button href="https://adminmart.com/product/modernize-angular-admin-dashboard/?ref=56#product-demo-section"
target="_blank" class="d-flex justify-content-center bg-success">
Check Pro Template
</a>
<button mat-mini-fab [matMenuTriggerFor]="profilemenu" aria-label="Notifications">
<img src="/assets/images/profile/user-1.jpg" class="rounded-circle object-cover d-block" width="35" />
</button>
<mat-menu #profilemenu="matMenu" class="cardWithShadow topbar-dd">
<button mat-menu-item>
<mat-icon class="d-flex align-items-center"><i-tabler name="user" class="icon-18 d-flex"></i-tabler></mat-icon>My
Profile
</button>
<button mat-menu-item>
<mat-icon class="d-flex align-items-center"><i-tabler name="mail" class="icon-18 d-flex"></i-tabler></mat-icon>My
Account
</button>
<button mat-menu-item>
<mat-icon class="d-flex align-items-center"><i-tabler name="list-check"
class="icon-18 d-flex"></i-tabler></mat-icon>My Task
</button>
<div class="p-x-12 m-t-12">
<a [routerLink]="['/authentication/login']" mat-stroked-button class="w-100">Logout</a>
</div>
</mat-menu>
</mat-toolbar>

View File

@@ -0,0 +1,30 @@
import {
Component,
Output,
EventEmitter,
Input,
ViewEncapsulation,
} from '@angular/core';
import { TablerIconsModule } from 'angular-tabler-icons';
import { MaterialModule } from 'src/app/material.module';
import { RouterModule } from '@angular/router';
import { CommonModule } from '@angular/common';
import { NgScrollbarModule } from 'ngx-scrollbar';
@Component({
selector: 'app-header',
imports: [
RouterModule,
CommonModule,
NgScrollbarModule,
TablerIconsModule,
MaterialModule,
],
templateUrl: './header.component.html',
encapsulation: ViewEncapsulation.None,
})
export class HeaderComponent {
@Input() showToggle = true;
@Input() toggleChecked = false;
@Output() toggleMobileNav = new EventEmitter<void>();
}

View File

@@ -0,0 +1,20 @@
import { Component } from '@angular/core';
import { CoreService } from 'src/app/services/core.service';
@Component({
selector: 'app-branding',
imports: [],
template: `
<a href="/" class="logodark">
<img
src="./assets/images/logos/dark-logo.svg"
class="align-middle m-2"
alt="logo"
/>
</a>
`,
})
export class BrandingComponent {
options = this.settings.getOptions();
constructor(private settings: CoreService) {}
}

View File

@@ -0,0 +1,48 @@
@if(item.navCap){
<div mat-subheader class="nav-caption">
{{ item.navCap }}
</div>
} @if(!item.navCap && !item.external) {
<a mat-list-item (click)="onItemSelected(item)" [ngClass]="{
activeMenu: item.route ? router.isActive(item.route, true) : false,
expanded: expanded,
disabled: item.disabled
}" class="menu-list-item">
<i-tabler class="routeIcon" name="{{ item.iconName }}" matListItemIcon></i-tabler>
<span class="hide-menu">{{ item.displayName }}</span>
@if(item.children && item.children.length) {
<span class="arrow-icon" fxFlex>
<span fxFlex></span>
@if(item.chip) {
<span>
<span class="{{ item.chipClass }} p-x-8 p-y-4 item-chip f-w-500 rounded-pill ">{{ item.chipContent }}</span>
</span>
}
<mat-icon [@indicatorRotate]="expanded ? 'expanded' : 'collapsed'">
expand_more
</mat-icon>
</span>
}
</a>
}
<!-- external Link -->
@if(!item.navCap && item.external) {
<mat-list-item (click)="openExternalLink(item.route)" class="menu-list-item" target="_blank">
<i-tabler class="routeIcon" name="{{ item.iconName }}" matListItemIcon></i-tabler>
<span class="hide-menu">{{ item.displayName }} </span>
@if(item.chip) {
<span>
<span class="{{ item.chipClass }} p-x-8 p-y-4 item-chip f-w-500 rounded-pill ">{{ item.chipContent }}</span>
</span>
}
</mat-list-item>
}
<!-- children -->
@if(expanded) { @for(child of item.children; track child) {
<app-nav-item [item]="child" (click)="onSubItemSelected(child)" [depth]="depth + 1">
</app-nav-item>
} }

View File

@@ -0,0 +1,77 @@
import {
Component,
HostBinding,
Input,
OnChanges,
Output,
EventEmitter,
} from '@angular/core';
import { NavItem } from './nav-item';
import { Router } from '@angular/router';
import { NavService } from '../../../../services/nav.service';
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: [],
})
export class AppNavItemComponent implements OnChanges {
@Output() notify: EventEmitter<boolean> = new EventEmitter<boolean>();
@Input() item: NavItem | any;
expanded: any = false;
@HostBinding('attr.aria-expanded') ariaExpanded = this.expanded;
@Input() depth: any;
constructor(public navService: NavService, public router: Router) {}
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();
}
}
}
openExternalLink(url: string): void {
if (url) {
window.open(url, '_blank');
}
}
onSubItemSelected(item: NavItem) {
if (!item.children || !item.children.length) {
if (this.expanded && window.innerWidth < 1024) {
this.notify.emit();
}
}
}
}

View File

@@ -0,0 +1,11 @@
export interface NavItem {
displayName?: string;
iconName?: string;
navCap?: string;
route?: string;
children?: NavItem[];
chip?: boolean;
chipContent?: string;
chipClass?: string;
external?: boolean;
}

View File

@@ -0,0 +1,914 @@
import { NavItem } from './nav-item/nav-item';
export const navItems: NavItem[] = [
{
navCap: 'Home',
},
{
displayName: 'Dashboard',
iconName: 'layout-grid-add',
route: '/dashboard',
},
{
displayName: 'Analytical',
iconName: 'aperture',
route: 'https://modernize-angular-main.netlify.app/dashboards/dashboard1',
chip: true,
external: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'eCommerce',
iconName: 'shopping-cart',
route: 'https://modernize-angular-main.netlify.app/dashboards/dashboard2',
chip: true,
external: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
navCap: 'Apps',
},
{
displayName: 'Chat',
iconName: 'message-dots',
route: 'https://modernize-angular-main.netlify.app/apps/chat',
chip: true,
external: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Calendar',
iconName: 'calendar',
route: 'https://modernize-angular-main.netlify.app/apps/calendar',
chip: true,
external: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Email',
iconName: 'mail',
route: 'https://modernize-angular-main.netlify.app/apps/email/inbox',
chip: true,
external: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Kanban',
iconName: 'checklist',
route: 'https://modernize-angular-main.netlify.app/apps/kanban',
chip: true,
external: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Contacts',
iconName: 'phone',
route: 'https://modernize-angular-main.netlify.app/apps/contacts',
chip: true,
external: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Contact List',
iconName: 'list-details',
route: 'https://modernize-angular-main.netlify.app/apps/contact-list',
chip: true,
external: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Courses',
iconName: 'certificate',
route: 'https://modernize-angular-main.netlify.app/apps/courses',
chip: true,
external: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Employee',
iconName: 'brand-ctemplar',
route: 'https://modernize-angular-main.netlify.app/apps/employee',
chip: true,
external: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Notes',
iconName: 'note',
route: 'https://modernize-angular-main.netlify.app/apps/notes',
chip: true,
external: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Tickets',
iconName: 'ticket',
route: 'https://modernize-angular-main.netlify.app/apps/tickets',
chip: true,
external: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'ToDo',
iconName: 'edit',
route: 'https://modernize-angular-main.netlify.app/apps/todo',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Invoice',
iconName: 'file-invoice',
chip: true,
route: '',
children: [
{
displayName: 'List',
iconName: 'point',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
route: '/https://modernize-angular-main.netlify.app/apps/invoice',
},
{
displayName: 'Detail',
iconName: 'point',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
route:
'/https://modernize-angular-main.netlify.app/apps/viewInvoice/101',
},
{
displayName: 'Create',
iconName: 'point',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
route: '/https://modernize-angular-main.netlify.app/apps/addInvoice',
},
{
displayName: 'Edit',
iconName: 'point',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
route:
'/https://modernize-angular-main.netlify.app/apps/editinvoice/101',
},
],
},
{
displayName: 'Blog',
iconName: 'chart-donut-3',
chip: true,
route: 'apps/blog',
children: [
{
displayName: 'Post',
iconName: 'point',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
route: 'https://modernize-angular-main.netlify.app/apps/blog/post',
},
{
displayName: 'Detail',
iconName: 'point',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
route:
'https://modernize-angular-main.netlify.app/apps/blog/detail/Early Black Friday Amazon deals: cheap TVs, headphones, laptops',
},
],
},
{
navCap: 'Ui Components',
},
{
displayName: 'Badge',
iconName: 'archive',
route: '/ui-components/badge',
},
{
displayName: 'Chips',
iconName: 'info-circle',
route: '/ui-components/chips',
},
{
displayName: 'Lists',
iconName: 'list-details',
route: '/ui-components/lists',
},
{
displayName: 'Menu',
iconName: 'file-text',
route: '/ui-components/menu',
},
{
displayName: 'Tooltips',
iconName: 'file-text-ai',
route: '/ui-components/tooltips',
},
{
displayName: 'Forms',
iconName: 'clipboard-text',
route: '/ui-components/forms',
},
{
displayName: 'Tables',
iconName: 'table',
route: '/ui-components/tables',
},
{
displayName: 'Expansion Panel',
iconName: 'layout-bottombar-inactive',
route: 'https://modernize-angular-main.netlify.app/ui-components/expansion',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Dialog',
iconName: 'diabolo',
route: 'https://modernize-angular-main.netlify.app/ui-components/dialog',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Divider',
iconName: 'separator',
route: 'https://modernize-angular-main.netlify.app/ui-components/divider',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Paginator',
iconName: 'text-wrap',
route: 'https://modernize-angular-main.netlify.app/ui-components/paginator',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Progress Bar',
iconName: 'progress',
route: 'https://modernize-angular-main.netlify.app/ui-components/progress',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Progress Spinner',
iconName: 'rotate-2',
route: 'https://modernize-angular-main.netlify.app/ui-components/progress-spinner',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Ripples',
iconName: 'ripple',
route: 'https://modernize-angular-main.netlify.app/ui-components/ripples',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Slide Toggle',
iconName: 'toggle-left',
route: 'https://modernize-angular-main.netlify.app/ui-components/slide-toggle',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Slider',
iconName: 'adjustments-alt',
route: 'https://modernize-angular-main.netlify.app/ui-components/slider',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Snackbar',
iconName: 'stack-backward',
route: 'https://modernize-angular-main.netlify.app/ui-components/snackbar',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Tabs',
iconName: 'border-all',
route: 'https://modernize-angular-main.netlify.app/ui-components/tabs',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Toolbar',
iconName: 'tools-kitchen',
route: 'https://modernize-angular-main.netlify.app/ui-components/toolbar',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Tooltips',
iconName: 'tooltip',
route: 'https://modernize-angular-main.netlify.app/ui-components/tooltips',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
navCap: 'Pages',
},
{
displayName: 'Roll Base Access',
iconName: 'lock-access',
route: 'https://modernize-angular-main.netlify.app/apps/permission',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Treeview',
iconName: 'git-merge',
route: 'https://modernize-angular-main.netlify.app/theme-pages/treeview',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Pricing',
iconName: 'currency-dollar',
route: 'https://modernize-angular-main.netlify.app/theme-pages/pricing',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Account Setting',
iconName: 'user-circle',
route:
'https://modernize-angular-main.netlify.app/theme-pages/account-setting',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'FAQ',
iconName: 'help',
route: 'https://modernize-angular-main.netlify.app/theme-pages/faq',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Landingpage',
iconName: 'app-window',
route: 'https://modernize-angular-main.netlify.app/landingpage',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Widgets',
iconName: 'layout',
route: 'widgets',
chip: true,
children: [
{
displayName: 'Cards',
iconName: 'point',
route: 'https://modernize-angular-main.netlify.app/widgets/cards',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Banners',
iconName: 'point',
route: 'https://modernize-angular-main.netlify.app/widgets/banners',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Charts',
iconName: 'point',
route: 'https://modernize-angular-main.netlify.app/widgets/charts',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
],
},
{
navCap: 'Extra',
},
{
displayName: 'Icons',
iconName: 'mood-smile',
route: '/extra/icons',
},
{
displayName: 'Sample Page',
iconName: 'brand-dribbble',
route: '/extra/sample-page',
},
{
navCap: 'Forms',
},
{
displayName: 'Elements',
iconName: 'apps',
chip: true,
route: 'forms/forms-elements',
children: [
{
displayName: 'Autocomplete',
iconName: 'point',
route:
'https://modernize-angular-main.netlify.app/forms/forms-elements/autocomplete',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Button',
iconName: 'point',
route:
'https://modernize-angular-main.netlify.app/forms/forms-elements/button',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Checkbox',
iconName: 'point',
route:
'https://modernize-angular-main.netlify.app/forms/forms-elements/checkbox',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Radio',
iconName: 'point',
route:
'https://modernize-angular-main.netlify.app/forms/forms-elements/radio',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Datepicker',
iconName: 'point',
route:
'https://modernize-angular-main.netlify.app/forms/forms-elements/datepicker',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
],
},
{
displayName: 'Form Layouts',
iconName: 'file-description',
route: 'https://modernize-angular-main.netlify.app/forms/form-layouts',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Form Horizontal',
iconName: 'box-align-bottom',
route: 'https://modernize-angular-main.netlify.app/forms/form-horizontal',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Form Vertical',
iconName: 'box-align-left',
route: 'https://modernize-angular-main.netlify.app/forms/form-vertical',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Form Wizard',
iconName: 'files',
route: 'https://modernize-angular-main.netlify.app/forms/form-wizard',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Toastr',
iconName: 'notification',
route: 'https://modernize-angular-main.netlify.app/forms/form-toastr',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
navCap: 'Tables',
},
{
displayName: 'Tables',
iconName: 'layout',
route: 'tables',
chip: true,
children: [
{
displayName: 'Basic Table',
iconName: 'point',
route: 'https://modernize-angular-main.netlify.app/tables/basic-table',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Dynamic Table',
iconName: 'point',
route: 'https://modernize-angular-main.netlify.app/tables/dynamic-table',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Expand Table',
iconName: 'point',
route: 'https://modernize-angular-main.netlify.app/tables/expand-table',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Filterable Table',
iconName: 'point',
route:
'https://modernize-angular-main.netlify.app/tables/filterable-table',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Footer Row Table',
iconName: 'point',
route:
'https://modernize-angular-main.netlify.app/tables/footer-row-table',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'HTTP Table',
iconName: 'point',
route: 'https://modernize-angular-main.netlify.app/tables/http-table',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Mix Table',
iconName: 'point',
route: 'https://modernize-angular-main.netlify.app/tables/mix-table',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Multi Header Footer',
iconName: 'point',
route:
'https://modernize-angular-main.netlify.app/tables/multi-header-footer-table',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Pagination Table',
iconName: 'point',
route:
'https://modernize-angular-main.netlify.app/tables/pagination-table',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Row Context Table',
iconName: 'point',
route:
'https://modernize-angular-main.netlify.app/tables/row-context-table',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Selection Table',
iconName: 'point',
route:
'https://modernize-angular-main.netlify.app/tables/selection-table',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Sortable Table',
iconName: 'point',
route:
'https://modernize-angular-main.netlify.app/tables/sortable-table',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Sticky Column',
iconName: 'point',
route:
'https://modernize-angular-main.netlify.app/tables/sticky-column-table',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Sticky Header Footer',
iconName: 'point',
route:
'https://modernize-angular-main.netlify.app/tables/sticky-header-footer-table',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
],
},
{
displayName: 'Data table',
iconName: 'border-outer',
route: 'https://modernize-angular-main.netlify.app/datatable/kichen-sink',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
navCap: 'Chart',
},
{
displayName: 'Line',
iconName: 'chart-line',
route: 'https://modernize-angular-main.netlify.app/charts/line',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Gredient',
iconName: 'chart-arcs',
route: 'https://modernize-angular-main.netlify.app/charts/gredient',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Area',
iconName: 'chart-area',
route: 'https://modernize-angular-main.netlify.app/charts/area',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Candlestick',
iconName: 'chart-candle',
route: 'https://modernize-angular-main.netlify.app/charts/candlestick',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Column',
iconName: 'chart-dots',
route: 'https://modernize-angular-main.netlify.app/charts/column',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Doughnut & Pie',
iconName: 'chart-donut-3',
route: 'https://modernize-angular-main.netlify.app/charts/doughnut-pie',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Radialbar & Radar',
iconName: 'chart-radar',
route: 'https://modernize-angular-main.netlify.app/charts/radial-radar',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
navCap: 'Auth',
},
{
displayName: 'Login',
iconName: 'login',
route: '/authentication',
children: [
{
displayName: 'Login',
iconName: 'point',
route: '/authentication/login',
},
{
displayName: 'Side Login',
iconName: 'point',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
route: 'https://modernize-angular-main.netlify.app/authentication/login',
},
],
},
{
displayName: 'Register',
iconName: 'user-plus',
route: '/authentication',
children: [
{
displayName: 'Register',
iconName: 'point',
route: '/authentication/register',
},
{
displayName: 'Side Register',
iconName: 'point',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
route: 'https://modernize-angular-main.netlify.app/authentication/side-register',
},
],
},
{
displayName: 'Forgot Pwd',
iconName: 'rotate',
chip: true,
route: '/authentication',
children: [
{
displayName: 'Side Forgot Pwd',
iconName: 'point',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
route: 'https://modernize-angular-main.netlify.app/authentication/side-forgot-pwd',
},
{
displayName: 'Boxed Forgot Pwd',
iconName: 'point',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
route: 'https://modernize-angular-main.netlify.app/authentication/boxed-forgot-pwd',
},
],
},
{
displayName: 'Two Steps',
iconName: 'zoom-code',
chip: true,
route: '/authentication',
children: [
{
displayName: 'Side Two Steps',
iconName: 'point',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
route: 'https://modernize-angular-main.netlify.app/authentication/side-two-steps',
},
{
displayName: 'Boxed Two Steps',
iconName: 'point',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
route: 'https://modernize-angular-main.netlify.app/authentication/boxed-two-steps',
},
],
},
{
displayName: 'Error',
iconName: 'alert-circle',
route: 'https://modernize-angular-main.netlify.app//authentication/error',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
{
displayName: 'Maintenance',
iconName: 'settings',
route: 'https://modernize-angular-main.netlify.app//authentication/maintenance',
external: true,
chip: true,
chipClass: 'bg-light-secondary text-secondary',
chipContent: 'PRO',
},
];

View File

@@ -0,0 +1,10 @@
<div class="d-flex align-items-center justify-content-between">
<div class="branding"><app-branding></app-branding></div>
@if(showToggle) {
<a href="javascript:void(0)" (click)="toggleMobileNav.emit()"
class="d-flex justify-content-center ng-star-inserted icon-40 align-items-center">
<i-tabler name="x" class="icon-20 d-flex"></i-tabler>
</a>
}
</div>

View File

@@ -0,0 +1,25 @@
import {
Component,
EventEmitter,
Input,
OnInit,
Output,
ViewChild,
} from '@angular/core';
import { BrandingComponent } from './branding.component';
import { TablerIconsModule } from 'angular-tabler-icons';
import { MaterialModule } from 'src/app/material.module';
@Component({
selector: 'app-sidebar',
imports: [BrandingComponent, TablerIconsModule, MaterialModule],
templateUrl: './sidebar.component.html',
})
export class SidebarComponent implements OnInit {
constructor() {}
@Input() showToggle = true;
@Output() toggleMobileNav = new EventEmitter<void>();
@Output() toggleCollapsed = new EventEmitter<void>();
ngOnInit(): void {}
}

View File

@@ -0,0 +1,121 @@
<div class="app-topstrip bg-dark text-white p-y-16 p-x-24 w-100 d-flex align-items-center justify-content-between">
<div class="d-none d-sm-flex align-items-center justify-content-center gap-20">
<a class="d-flex align-items-center" href="https://adminmart.com/" target="_blank">
<img src="/assets/images/logos/logo-adminmart.svg" alt="" width="150">
</a>
<div class="linkbar d-none d-lg-flex align-items-center justify-content-center gap-16">
<!-- Templates -->
<a mat-button class="link-hover p-x-0 text-white d-flex" href="https://adminmart.com/templates/angular/"
target="_blank">
<div class="d-flex align-items-center gap-8 f-s-16 f-w-400">
<i class="iconify icon-20 d-flex" data-icon="solar:window-frame-linear"></i>
Templates
</div>
</a>
<!-- Support -->
<a mat-button class="link-hover p-x-0 text-white d-flex" href="https://adminmart.com/support/"
target="_blank">
<div class="d-flex align-items-center gap-8 f-s-16 f-w-400">
<i class="iconify icon-20 d-flex" data-icon="solar:question-circle-linear"></i>
Help
</div>
</a>
<!-- Hire Us -->
<a mat-button class="link-hover p-x-0 text-white d-flex" href="https://adminmart.com/hire-us/"
target="_blank">
<div class="d-flex align-items-center gap-8 f-s-16 f-w-400">
<i class="iconify icon-20 d-flex" data-icon="solar:case-round-linear"></i>
Hire Us
</div>
</a>
</div>
</div>
<div class="topstrip-right d-flex align-items-center justify-content-center gap-16">
<h6 class="text-linear-gradient f-s-14 text-uppercase text-lg-left text-center">Checkout Pro Version</h6>
<div class="topstrip-right-inner d-flex justify-content-center align-items-center gap-10">
<div class="d-flex justify-content-center align-items-center gap-10">
<!-- Live Preview -->
<button class="live-preview-drop d-flex align-items-center gap-4 text-white f-s-16 p-x-16" mat-button
[matMenuTriggerFor]="beforeMenu">
<div class="d-flex align-items-center gap-6">
Live Preview
<i class="iconify icon-20 d-flex" data-icon="solar:alt-arrow-down-linear"></i>
</div>
</button>
<mat-menu class="p-x-16 p-y-8 rounded-7" #beforeMenu="matMenu" xPosition="before">
<a mat-menu-item class="rounded-7"
href="https://adminmart.com/product/modernize-angular-material-dashboard/?ref=56#product-demo-section"
target="_blank">
<div class="d-flex align-items-center gap-12 f-s-16">
<img src="/assets/images/svgs/angular-cat-icon.svg" width="18" alt="angular">
Angular Version
</div>
</a>
<a mat-menu-item class="rounded-7"
href="https://adminmart.com/product/modernize-react-mui-dashboard-theme/?ref=56#product-demo-section"
target="_blank">
<div class="d-flex align-items-center gap-12 f-s-16">
<img src="/assets/images/svgs/react-cat-icon.svg" width="18" alt="react">
React Version
</div>
</a>
<a mat-menu-item class="rounded-7"
href="https://adminmart.com/product/modernize-vuetify-vue-admin-dashboard/?ref=56#product-demo-section"
target="_blank">
<div class="d-flex align-items-center gap-12 f-s-16">
<img src="/assets/images/svgs/vue-cat-icon.svg" width="18" alt="vueJs">
VueJs Version
</div>
</a>
<a mat-menu-item class="rounded-7"
href="https://adminmart.com/product/modernize-next-js-admin-dashboard/?ref=56#product-demo-section"
target="_blank">
<div class="d-flex align-items-center gap-12 f-s-16">
<img src="/assets/images/svgs/next-cat-icon.svg" width="18" alt="nextJs">
NextJs Version
</div>
</a>
<a mat-menu-item class="rounded-7"
href="https://adminmart.com/product/modernize-nuxt-js-admin-dashboard/?ref=56#product-demo-section"
target="_blank">
<div class="d-flex align-items-center gap-12 f-s-16">
<img src="/assets/images/svgs/nuxt-cat-icon.svg" width="18" alt="nuxtJs">
NuxtJs Version
</div>
</a>
<a mat-menu-item class="rounded-7"
href="https://adminmart.com/product/modernize-tailwind-nextjs-dashboard-template/?ref=56#product-demo-section"
target="_blank">
<div class="d-flex align-items-center gap-12 f-s-16">
<img src="/assets/images/svgs/tailwindcss.svg" width="20" alt="tailwind">
Tailwind Version
</div>
</a>
<a mat-menu-item class="rounded-7"
href="https://adminmart.com/product/modernize-bootstrap-5-admin-template/?ref=56#product-demo-section"
target="_blank">
<div class="d-flex align-items-center gap-12 f-s-16">
<img src="/assets/images/svgs/bt-cat-icon.svg" width="20" alt="bootstrap">
Bootstrap Version
</div>
</a>
</mat-menu>
<!-- Get Pro -->
<a mat-button class="get-pro-btn text-white p-x-16"
href="https://adminmart.com/product/modernize-angular-material-dashboard/?ref=56" target="_blank">
<div class="d-flex align-items-center gap-8 f-s-16 f-w-400">
<i class="iconify icon-18 d-flex" data-icon="solar:crown-linear"></i>
Get Pro
</div>
</a>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,15 @@
import { Component } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatMenuModule } from '@angular/material/menu';
import { TablerIconsModule } from 'angular-tabler-icons';
@Component({
selector: 'app-topstrip',
imports: [TablerIconsModule, MatButtonModule, MatMenuModule],
templateUrl: './topstrip.component.html',
})
export class AppTopstripComponent {
constructor() { }
}

View File

@@ -0,0 +1,85 @@
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: [],
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,20 @@
import { Routes } from '@angular/router';
import { AppSideLoginComponent } from './side-login/side-login.component';
import { AppSideRegisterComponent } from './side-register/side-register.component';
export const AuthenticationRoutes: Routes = [
{
path: '',
children: [
{
path: 'login',
component: AppSideLoginComponent,
},
{
path: 'register',
component: AppSideRegisterComponent,
},
],
},
];

View File

@@ -0,0 +1,64 @@
<div class="blank-layout-container justify-content-center align-items-center bg-light">
<div class="position-relative row w-100 h-100 bg-gredient justify-content-center">
<div class="col-lg-4 d-flex align-items-center">
<mat-card class="cardWithShadow boxed-auth">
<mat-card-content class="p-32">
<div class="text-center">
<a [routerLink]="['/dashboard']">
<img src="./assets/images/logos/dark-logo.svg" class="align-middle m-2" alt="logo" />
</a>
</div>
<div class="row m-t-24 custom-row">
<div class="col-12 col-sm-6">
<button mat-stroked-button class="w-100">
<div class="d-flex align-items-center">
<img src="/assets/images/svgs/google-icon.svg" alt="google" width="16" class="m-r-8" />
<span>
Sign in with Google
</span>
</div>
</button>
</div>
<div class="col-12 col-sm-6">
<button mat-stroked-button class="w-100 d-flex align-items-center">
<div class="d-flex align-items-center">
<img src="/assets/images/svgs/facebook-icon.svg" alt="facebook" width="40" class="m-r-4" />
Sign in with FB
</div>
</button>
</div>
</div>
<div class="or-border m-t-30">or sign in with</div>
<form class="m-t-30">
<mat-label class="f-s-14 f-w-600 m-b-12 d-block">Username</mat-label>
<mat-form-field appearance="outline" class="w-100" color="primary">
<input matInput />
</mat-form-field>
<!-- password -->
<mat-label class="f-s-14 f-w-600 m-b-12 d-block">Password</mat-label>
<mat-form-field appearance="outline" class="w-100" color="primary">
<input matInput type="password" />
</mat-form-field>
<div class="d-flex align-items-center m-b-12">
<mat-checkbox color="primary">Remember this Device</mat-checkbox>
<a [routerLink]="['/']" class="text-primary f-w-600 text-decoration-none m-l-auto f-s-14">Forgot Password
?</a>
</div>
<a [routerLink]="['/']" mat-flat-button color="primary" class="w-100">
Sign In
</a>
<!-- input -->
</form>
<span class="d-block f-w-500 text-center m-t-24">New to Modernize?
<a [routerLink]="['/authentication/register']" class="text-decoration-none text-primary f-w-500 f-s-14">
Create an account</a>
</span>
</mat-card-content>
</mat-card>
</div>
</div>
</div>

View File

@@ -0,0 +1,31 @@
import { Component } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { RouterModule } from '@angular/router';
import { MaterialModule } from 'src/app/material.module';
import { FormsModule } from '@angular/forms';
import { ReactiveFormsModule } from '@angular/forms';
@Component({
selector: 'app-side-login',
imports: [RouterModule, MaterialModule, FormsModule, ReactiveFormsModule],
templateUrl: './side-login.component.html',
})
export class AppSideLoginComponent {
constructor( private router: Router) {}
form = new FormGroup({
uname: new FormControl('', [Validators.required, Validators.minLength(6)]),
password: new FormControl('', [Validators.required]),
});
get f() {
return this.form.controls;
}
submit() {
// console.log(this.form.value);
this.router.navigate(['/']);
}
}

View File

@@ -0,0 +1,62 @@
<div class="blank-layout-container justify-content-center align-items-center bg-light">
<div class="position-relative row w-100 h-100 bg-gredient justify-content-center">
<div class="col-lg-4 d-flex align-items-center">
<mat-card class="cardWithShadow boxed-auth">
<mat-card-content class="p-32">
<div class="text-center">
<a [routerLink]="['/dashboard']">
<img src="./assets/images/logos/dark-logo.svg" class="align-middle m-2" alt="logo" />
</a>
</div>
<div class="row m-t-24 custom-row">
<div class="col-12 col-sm-6">
<button mat-stroked-button class="w-100">
<div class="d-flex align-items-center">
<img src="/assets/images/svgs/google-icon.svg" alt="google" width="16" class="m-r-8" />
Sign in with Google
</div>
</button>
</div>
<div class="col-12 col-sm-6">
<button mat-stroked-button class="w-100 d-flex align-items-center">
<div class="d-flex align-items-center">
<img src="/assets/images/svgs/facebook-icon.svg" alt="facebook" width="40" class="m-r-4" />
Sign in with FB
</div>
</button>
</div>
</div>
<div class="or-border m-t-30">or sign up with</div>
<form class="m-t-30">
<mat-label class="f-s-14 f-w-600 m-b-12 d-block">Name</mat-label>
<mat-form-field appearance="outline" class="w-100" color="primary">
<input matInput />
</mat-form-field>
<mat-label class="f-s-14 f-w-600 m-b-12 d-block">Email Adddress</mat-label>
<mat-form-field appearance="outline" class="w-100" color="primary">
<input matInput type="email" />
</mat-form-field>
<!-- password -->
<mat-label class="f-s-14 f-w-600 m-b-12 d-block">Password</mat-label>
<mat-form-field appearance="outline" class="w-100" color="primary">
<input matInput type="password" />
</mat-form-field>
<a [routerLink]="['/']" mat-flat-button color="primary" class="w-100">
Sign Up
</a>
<!-- input -->
</form>
<span class="d-block f-w-500 text-center m-t-24">Already have an Account?
<a [routerLink]="['/authentication/login']" class="text-decoration-none text-primary f-w-500 f-s-14">
Sign In</a>
</span>
</mat-card-content>
</mat-card>
</div>
</div>
</div>

View File

@@ -0,0 +1,33 @@
import { Component } from '@angular/core';
import { CoreService } from 'src/app/services/core.service';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { MaterialModule } from 'src/app/material.module';
@Component({
selector: 'app-side-register',
imports: [RouterModule, MaterialModule, FormsModule, ReactiveFormsModule],
templateUrl: './side-register.component.html',
})
export class AppSideRegisterComponent {
options = this.settings.getOptions();
constructor(private settings: CoreService, private router: Router) {}
form = new FormGroup({
uname: new FormControl('', [Validators.required, Validators.minLength(6)]),
email: new FormControl('', [Validators.required]),
password: new FormControl('', [Validators.required]),
});
get f() {
return this.form.controls;
}
submit() {
// console.log(this.form.value);
this.router.navigate(['/']);
}
}

View File

@@ -0,0 +1,22 @@
import { Routes } from '@angular/router';
// pages
import { AppIconsComponent } from './icons/icons.component';
import { AppSamplePageComponent } from './sample-page/sample-page.component';
export const ExtraRoutes: Routes = [
{
path: '',
children: [
{
path: 'icons',
component: AppIconsComponent,
},
{
path: 'sample-page',
component: AppSamplePageComponent,
},
],
},
];

View File

@@ -0,0 +1,12 @@
<!-- ============================================================== -->
<!-- Simple four boxes Row -->
<!-- ============================================================== -->
<mat-card class="cardWithShadow">
<mat-card-content>
<mat-card-title>Icons</mat-card-title>
<mat-card-subtitle class="m-b-24">Tabler Icons</mat-card-subtitle>
<iframe src="https://tabler.io/icons" title="Tabler Icons" width="100%" height="630px"
allowfullscreen frameBorder="0">
</iframe>
</mat-card-content>
</mat-card>

View File

@@ -0,0 +1,9 @@
import { Component } from '@angular/core';
import { MaterialModule } from '../../../material.module';
@Component({
selector: 'app-icons',
imports: [MaterialModule],
templateUrl: './icons.component.html',
})
export class AppIconsComponent { }

View File

@@ -0,0 +1,9 @@
<!-- ============================================================== -->
<!-- Simple four boxes Row -->
<!-- ============================================================== -->
<mat-card class="cardWithShadow">
<mat-card-content>
<mat-card-title>Sample Page</mat-card-title>
<mat-card-subtitle>This is test page</mat-card-subtitle>
</mat-card-content>
</mat-card>

View File

@@ -0,0 +1,10 @@
import { Component } from '@angular/core';
import { MaterialModule } from '../../../material.module';
@Component({
selector: 'app-sample-page',
imports: [MaterialModule],
templateUrl: './sample-page.component.html',
})
export class AppSamplePageComponent { }

View File

@@ -0,0 +1,16 @@
import { Routes } from '@angular/router';
import { StarterComponent } from './starter/starter.component';
export const PagesRoutes: Routes = [
{
path: '',
component: StarterComponent,
data: {
title: 'Starter Page',
urls: [
{ title: 'Dashboard', url: '/dashboards/dashboard1' },
{ title: 'Starter Page' },
],
},
},
];

View File

@@ -0,0 +1,24 @@
<div class="row">
<div class="col-lg-8">
<app-sales-overview></app-sales-overview>
</div>
<div class="col-lg-4">
<app-yearly-breakup></app-yearly-breakup>
<app-monthly-earnings></app-monthly-earnings>
</div>
</div>
<div class="row">
<div class="col-lg-4">
<app-recent-transactions></app-recent-transactions>
</div>
<div class="col-lg-8">
<app-product-performance></app-product-performance>
</div>
</div>
<div class="row">
<div class="col-12">
<app-blog-card></app-blog-card>
</div>
</div>

View File

@@ -0,0 +1,25 @@
import { Component, ViewEncapsulation } from '@angular/core';
import { MaterialModule } from '../../material.module';
import { AppSalesOverviewComponent } from 'src/app/components/sales-overview/sales-overview.component';
import { AppYearlyBreakupComponent } from 'src/app/components/yearly-breakup/yearly-breakup.component';
import { AppMonthlyEarningsComponent } from 'src/app/components/monthly-earnings/monthly-earnings.component';
import { AppRecentTransactionsComponent } from 'src/app/components/recent-transactions/recent-transactions.component';
import { AppProductPerformanceComponent } from 'src/app/components/product-performance/product-performance.component';
import { AppBlogCardsComponent } from 'src/app/components/blog-card/blog-card.component';
@Component({
selector: 'app-starter',
imports: [
MaterialModule,
AppSalesOverviewComponent,
AppYearlyBreakupComponent,
AppMonthlyEarningsComponent,
AppRecentTransactionsComponent,
AppProductPerformanceComponent,
AppBlogCardsComponent
],
templateUrl: './starter.component.html',
encapsulation: ViewEncapsulation.None,
})
export class StarterComponent { }

View File

@@ -0,0 +1,51 @@
<mat-card class="cardWithShadow theme-card">
<mat-card-header>
<mat-card-title class="m-b-0">Badges</mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<mat-card class="b-1 shadow-none">
<mat-card-content>
<div matBadge="4" matBadgeOverlap="false" class="d-inline">Text with a badge</div>
</mat-card-content>
</mat-card>
<mat-card class="b-1 shadow-none">
<mat-card-content>
<div matBadge="1" matBadgeSize="small" class="d-inline">Text with small badge</div><br /><br />
<div matBadge="1" matBadgeSize="large" class="d-inline">Text with large badge</div>
</mat-card-content>
</mat-card>
<mat-card class="b-1 shadow-none">
<mat-card-content>
<p class="f-w-500 text-muted">
Button with a badge on the left
<button mat-flat-button color="primary" matBadge="8" matBadgePosition="before" matBadgeColor="accent">
Action
</button>
</p>
</mat-card-content>
</mat-card>
<mat-card class="b-1 shadow-none">
<mat-card-content>
<p class="f-w-500 text-muted">
Icon with a badge
<mat-icon matBadge="15" matBadgeColor="warn">home</mat-icon>
</p>
</mat-card-content>
</mat-card>
<mat-card class="b-1 shadow-none">
<mat-card-content>
<p>
Button toggles badge visibility
<button mat-flat-button color="primary" matBadge="7" [matBadgeHidden]="hidden"
(click)="toggleBadgeVisibility()">
Hide
</button>
</p>
</mat-card-content>
</mat-card>
</mat-card-content>
</mat-card>

View File

@@ -0,0 +1,22 @@
import { Component, OnInit } from '@angular/core';
import { MatIconModule } from '@angular/material/icon';
import { MatButtonModule } from '@angular/material/button';
import { MatBadgeModule } from '@angular/material/badge';
import { MatCardModule } from '@angular/material/card';
@Component({
selector: 'app-badge',
templateUrl: './badge.component.html',
imports: [MatBadgeModule, MatButtonModule, MatIconModule, MatCardModule],
})
export class AppBadgeComponent implements OnInit {
constructor() {}
ngOnInit(): void {}
hidden = false;
toggleBadgeVisibility() {
this.hidden = !this.hidden;
}
}

View File

@@ -0,0 +1,172 @@
<mat-card class="cardWithShadow theme-card">
<mat-card-header>
<mat-card-title class="m-b-0">Chips</mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<div class="row">
<div class="col-lg-6">
<!-- ------------------------------------------------------------------------- -->
<!-- basic -->
<!-- ------------------------------------------------------------------------- -->
<mat-card class="b-1 shadow-none">
<mat-card-header>
<mat-card-title>Basic</mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<mat-chip-listbox aria-label="Fish selection">
<mat-chip-option class="f-s-14" color="primary">One fish</mat-chip-option>
<mat-chip-option class="f-s-14">Two fish</mat-chip-option>
<mat-chip-option class="f-s-14" color="accent" selected>Accent fish</mat-chip-option>
<mat-chip-option class="f-s-14" color="warn">Warn fish</mat-chip-option>
</mat-chip-listbox>
</mat-card-content>
</mat-card>
</div>
<div class="col-lg-6">
<!-- ------------------------------------------------------------------------- -->
<!-- avatar -->
<!-- ------------------------------------------------------------------------- -->
<mat-card class="b-1 shadow-none">
<mat-card-header>
<mat-card-title>Avatar</mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<mat-chip-set aria-label="Dog selection">
<mat-chip class="f-s-14">
<img matChipAvatar src="/assets/images/profile/user-1.jpg" alt="Photo of a Shiba Inu" />
Anderson
</mat-chip>
<mat-chip class="f-s-14" color="primary">
<img matChipAvatar src="/assets/images/profile/user-2.jpg" alt="Photo of a Shiba Inu" />
Monty
</mat-chip>
<mat-chip class="f-s-14" color="accent">
<img matChipAvatar src="/assets/images/profile/user-3.jpg" alt="Photo of a Shiba Inu" />
Mathew
</mat-chip>
</mat-chip-set>
</mat-card-content>
</mat-card>
</div>
<div class="col-lg-6">
<!-- ------------------------------------------------------------------------- -->
<!-- Drag n Drop -->
<!-- ------------------------------------------------------------------------- -->
<mat-card class="b-1 shadow-none">
<mat-card-header>
<mat-card-title>Drag n Drop</mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<mat-chip-set class="example-chip" cdkDropList cdkDropListOrientation="horizontal"
(cdkDropListDropped)="drop($event)">
@for (vegetable of vegetables(); track vegetable.name) {
<mat-chip class="example-box" cdkDrag>{{
vegetable.name
}}</mat-chip>
}
</mat-chip-set>
</mat-card-content>
</mat-card>
</div>
<div class="col-lg-6">
<!-- ------------------------------------------------------------------------- -->
<!-- Stacked -->
<!-- ------------------------------------------------------------------------- -->
<mat-card class="b-1 shadow-none">
<mat-card-header>
<mat-card-title>Stacked </mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<mat-chip-listbox class="mat-mdc-chip-set-stacked" aria-label="Color selection">
@for(chip of availableColors; track chip.color) {
<mat-chip-option selected [color]="chip.color">
{{ chip.name }}
</mat-chip-option>
}
</mat-chip-listbox>
</mat-card-content>
</mat-card>
</div>
<div class="col-12">
<!-- ------------------------------------------------------------------------- -->
<!-- Input -->
<!-- ------------------------------------------------------------------------- -->
<mat-card class="b-1 shadow-none">
<mat-card-header>
<mat-card-title>Input</mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<mat-form-field appearance="outline" class="w-100">
<mat-label>Favorite Fruits</mat-label>
<mat-chip-grid #chipGrid aria-label="Enter fruits">
@for(fruit of fruits; track fruit.name) {
<mat-chip-row (removed)="remove(fruit)" [editable]="true" (edited)="edit(fruit, $event)"
[aria-description]="'press enter to edit ' + fruit.name" class="f-s-14">
{{ fruit.name }}
<button matChipRemove [attr.aria-label]="'remove ' + fruit.name">
<mat-icon>cancel</mat-icon>
</button>
</mat-chip-row>
}
<input placeholder="New fruit..." [matChipInputFor]="chipGrid"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputAddOnBlur]="addOnBlur"
(matChipInputTokenEnd)="add($event)" />
</mat-chip-grid>
</mat-form-field>
</mat-card-content>
</mat-card>
</div>
<div class="col-12">
<!-- ------------------------------------------------------------------------- -->
<!-- Form Control -->
<!-- ------------------------------------------------------------------------- -->
<mat-card class="b-1 shadow-none">
<mat-card-header>
<mat-card-title>Form Control</mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<div class="d-flex gap-8">
<button mat-stroked-button color="primary" (click)="formControl.disable()">
Disable form control
</button>
<button mat-raised-button color="primary" (click)="formControl.enable()">
Enable form control
</button>
</div>
<mat-form-field appearance="outline" class="w-100 m-t-20">
<mat-label>Video keywords</mat-label>
<mat-chip-grid #formChip aria-label="Enter keywords" [formControl]="formControl">
@for (keyword of keywords(); track keyword) {
<mat-chip-row (removed)="removeKeyword(keyword)">
{{ keyword }}
<button matChipRemove aria-label="'remove ' + keyword">
<mat-icon>cancel</mat-icon>
</button>
</mat-chip-row>
}
</mat-chip-grid>
<input placeholder="New keyword..." [matChipInputFor]="formChip"
(matChipInputTokenEnd)="addForm($event)" />
</mat-form-field>
<p>
<span class="f-w-600">The following keywords are entered:</span>
{{ formControl.value }}
</p>
</mat-card-content>
</mat-card>
</div>
</div>
</mat-card-content>
</mat-card>

View File

@@ -0,0 +1,7 @@
.example-box.cdk-drag-animating {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}
.example-chip .cdk-drop-list-dragging {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}

View File

@@ -0,0 +1,161 @@
import { COMMA, ENTER } from '@angular/cdk/keycodes';
import { ThemePalette } from '@angular/material/core';
import {
ChangeDetectionStrategy,
Component,
inject,
signal,
} from '@angular/core';
import {
CdkDrag,
CdkDragDrop,
CdkDropList,
moveItemInArray,
} from '@angular/cdk/drag-drop';
import { MatCardModule } from '@angular/material/card';
import {
MatChipEditedEvent,
MatChipInputEvent,
MatChipsModule,
} from '@angular/material/chips';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon';
import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { LiveAnnouncer } from '@angular/cdk/a11y';
import { MatButtonModule } from '@angular/material/button';
export interface ChipColor {
name: string;
color: ThemePalette;
}
export interface Fruit {
name: string;
}
export interface Vegetable {
name: string;
}
@Component({
selector: 'app-chips',
templateUrl: './chips.component.html',
styleUrls: ['./chips.component.scss'],
imports: [
MatFormFieldModule,
MatChipsModule,
MatIconModule,
MatCardModule,
CdkDropList,
CdkDrag,
FormsModule,
ReactiveFormsModule,
MatButtonModule
],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppChipsComponent {
// drag n drop
readonly vegetables = signal<Vegetable[]>([
{ name: 'apple' },
{ name: 'banana' },
{ name: 'strawberry' },
{ name: 'orange' },
{ name: 'kiwi' },
{ name: 'cherry' },
]);
drop(event: CdkDragDrop<Vegetable[]>) {
this.vegetables.update((vegetables) => {
moveItemInArray(vegetables, event.previousIndex, event.currentIndex);
return [...vegetables];
});
}
//
// Stacked
//
availableColors: ChipColor[] = [
{ name: 'Primary', color: 'primary' },
{ name: 'Accent', color: 'accent' },
{ name: 'Warn', color: 'warn' },
];
//
// chips with input
//
addOnBlur = true;
readonly separatorKeysCodes = [ENTER, COMMA] as const;
fruits: Fruit[] = [{ name: 'Lemon' }, { name: 'Lime' }, { name: 'Apple' }];
add(event: MatChipInputEvent): void {
const value = (event.value || '').trim();
// Add our fruit
if (value) {
this.fruits.push({ name: value });
}
// Clear the input value
event.chipInput!.clear();
}
remove(fruit: Fruit): void {
const index = this.fruits.indexOf(fruit);
if (index >= 0) {
this.fruits.splice(index, 1);
}
}
edit(fruit: Fruit, event: MatChipEditedEvent) {
const value = event.value.trim();
// Remove fruit if it no longer has a name
if (!value) {
this.remove(fruit);
return;
}
// Edit existing fruit
const index = this.fruits.indexOf(fruit);
if (index >= 0) {
this.fruits[index].name = value;
}
}
// form control
readonly keywords = signal(['angular', 'how-to', 'tutorial', 'accessibility']);
readonly formControl = new FormControl(['angular']);
announcer = inject(LiveAnnouncer);
removeKeyword(keyword: string) {
this.keywords.update(keywords => {
const index = keywords.indexOf(keyword);
if (index < 0) {
return keywords;
}
keywords.splice(index, 1);
this.announcer.announce(`removed ${keyword}`);
return [...keywords];
});
}
addForm(event: MatChipInputEvent): void {
const value = (event.value || '').trim();
// Add our keyword
if (value) {
this.keywords.update(keywords => [...keywords, value]);
}
// Clear the input value
event.chipInput!.clear();
}
}
function isDragDrop(object: any): object is CdkDragDrop<string[]> {
return 'previousIndex' in object;
}

View File

@@ -0,0 +1,73 @@
<mat-card class="cardWithShadow theme-card">
<mat-card-header>
<mat-card-title class="m-b-0">Form</mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<form>
<div class="row">
<div class="col-lg-6">
<!-- input -->
<mat-label class="f-w-600 m-b-8 d-block">Your Name</mat-label>
<mat-form-field appearance="outline" class="w-100" color="primary">
<input matInput placeholder="your name " />
</mat-form-field>
</div>
<div class="col-lg-6">
<mat-label class="f-w-600 m-b-8 d-block">Country</mat-label>
<mat-form-field appearance="outline" class="w-100">
<mat-select [(value)]="selectedCountry">
@for(option of country; track option.value) {
<mat-option [value]="option.value">{{
option.viewValue
}}</mat-option>
}
</mat-select>
</mat-form-field>
</div>
<div class="col-lg-6">
<!-- input -->
<mat-label class="f-w-600 m-b-8 d-block">Email</mat-label>
<mat-form-field appearance="outline" class="w-100" color="primary">
<input matInput type="email" placeholder="your email" />
</mat-form-field>
</div>
<div class="col-lg-6">
<mat-label class="f-w-600 m-b-8 d-block">State</mat-label>
<mat-form-field appearance="outline" class="w-100">
<mat-select [(value)]="selectedState">
@for(option of state; track option.value) {
<mat-option [value]="option.value">{{
option.viewValue
}}</mat-option>
}
</mat-select>
</mat-form-field>
</div>
<div class="col-lg-6">
<!-- input -->
<mat-label class="f-w-600 m-b-8 d-block">Password</mat-label>
<mat-form-field appearance="outline" class="w-100" color="primary">
<input matInput type="password" placeholder="your password" />
</mat-form-field>
</div>
<div class="col-lg-6">
<mat-label class="f-w-600 m-b-8 d-block">City</mat-label>
<mat-form-field appearance="outline" class="w-100">
<mat-select [(value)]="selectedCity">
@for(option of city; track option.value) {
<mat-option [value]="option.value">{{
option.viewValue
}}</mat-option>
}
</mat-select>
</mat-form-field>
</div>
</div>
<div class="m-t-12">
<button mat-flat-button color="primary" class="m-r-8">Submit</button>
<button mat-stroked-button color="warn">Cancel</button>
</div>
</form>
</mat-card-content>
</mat-card>

View File

@@ -0,0 +1,58 @@
import { Component } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { MatSelectModule } from '@angular/material/select';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatCardModule } from '@angular/material/card';
import { MatInputModule } from '@angular/material/input';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatRadioModule } from '@angular/material/radio';
interface Food {
value: string;
viewValue: string;
}
@Component({
selector: 'app-forms',
imports: [
MatFormFieldModule,
MatSelectModule,
FormsModule,
ReactiveFormsModule,
MatRadioModule,
MatButtonModule,
MatCardModule,
MatInputModule,
MatCheckboxModule,
],
templateUrl: './forms.component.html',
})
export class AppFormsComponent {
country: Food[] = [
{ value: 'steak-0', viewValue: 'USA' },
{ value: 'pizza-1', viewValue: 'India' },
{ value: 'tacos-2', viewValue: 'France' },
{ value: 'tacos-3', viewValue: 'UK' },
];
selectedCountry = this.country[2].value;
city: Food[] = [
{ value: 'steak-0', viewValue: 'Mexico' },
{ value: 'pizza-1', viewValue: 'Mumbai' },
{ value: 'tacos-2', viewValue: 'Tokyo' },
{ value: 'tacos-3', viewValue: 'New York' },
];
selectedCity = this.city[1].value;
state: Food[] = [
{ value: 'steak-0', viewValue: 'Cuba' },
{ value: 'pizza-1', viewValue: 'Djibouti' },
{ value: 'tacos-2', viewValue: 'Bulgaria' },
{ value: 'tacos-3', viewValue: 'Cabo Verde' },
];
selectedState = this.state[3].value;
}

View File

@@ -0,0 +1,197 @@
<mat-card class="cardWithShadow theme-card">
<mat-card-header>
<mat-card-title class="m-b-0">Lists</mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<div class="row">
<div class="col-lg-6">
<!-- --------------------------------------------------- -->
<!-- basic -->
<!-- --------------------------------------------------- -->
<mat-card class="b-1 shadow-none">
<mat-card-header>
<mat-card-title>Basic</mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<mat-list role="list">
<mat-list-item role="listitem">Item 1</mat-list-item>
<mat-list-item role="listitem">Item 2</mat-list-item>
<mat-list-item role="listitem">Item 3</mat-list-item>
</mat-list>
</mat-card-content>
</mat-card>
</div>
<div class="col-lg-6">
<!-- --------------------------------------------------- -->
<!-- two line -->
<!-- --------------------------------------------------- -->
<mat-card class="b-1 shadow-none">
<mat-card-header>
<mat-card-title>Two Line</mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<mat-list>
<mat-list-item>
<span matListItemTitle class="f-s-16 f-w-600">Title</span>
<span matListItemLine>Second line</span>
</mat-list-item>
<mat-list-item>
<span matListItemTitle class="f-s-16 f-w-600">Title</span>
<span matListItemLine>Second line</span>
</mat-list-item>
</mat-list>
</mat-card-content>
</mat-card>
</div>
<div class="col-lg-6">
<!-- --------------------------------------------------- -->
<!-- two line -->
<!-- --------------------------------------------------- -->
<mat-card class="b-1 shadow-none">
<mat-card-header>
<mat-card-title>Three Line</mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<mat-list>
<mat-list-item>
<span matListItemTitle class="f-s-16 f-w-600">Title</span>
<span matListItemLine>Second line</span>
<span matListItemLine>Third line</span>
</mat-list-item>
<mat-list-item>
<span matListItemTitle class="f-s-16 f-w-600">Title</span>
<span matListItemLine>Second line. This line will truncate.</span>
<span>Third line</span>
</mat-list-item>
</mat-list>
</mat-card-content>
</mat-card>
</div>
<div class="col-lg-6">
<!-- --------------------------------------------------- -->
<!-- two line -->
<!-- --------------------------------------------------- -->
<mat-card class="b-1 shadow-none">
<mat-card-header>
<mat-card-title>Three Line with Text wrapping</mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<mat-list style="max-width: 500px">
<mat-list-item lines="3">
<span matListItemTitle class="f-s-16 f-w-600">Title</span>
<span>Secondary line that will wrap because the list lines is
explicitly set to 3 lines. Text inside of a `matListItemTitle`
or `matListItemLine` will never wrap.
</span>
</mat-list-item>
<mat-list-item lines="3">
<span matListItemTitle class="f-s-16 f-w-600">Title</span>
<span>Secondary line that will wrap because the list lines is
explicitly set to 3 lines. Text inside of a `matListItemTitle`
or `matListItemLine` will never wrap.
</span>
</mat-list-item>
</mat-list>
</mat-card-content>
</mat-card>
</div>
<div class="col-lg-6">
<!-- --------------------------------------------------- -->
<!-- List with Selection -->
<!-- --------------------------------------------------- -->
<mat-card class="b-1 shadow-none">
<mat-card-header>
<mat-card-title>List with Selection</mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<mat-selection-list #shoes>
@for(shoe of typesOfShoes; track shoe) {
<mat-list-option>
{{ shoe }}
</mat-list-option>
}
</mat-selection-list>
<p class="f-w-600 p-16 bg-light-primary rounded">
Options selected: {{ shoes.selectedOptions.selected.length }}
</p>
</mat-card-content>
</mat-card>
</div>
<div class="col-lg-6">
<!-- --------------------------------------------------- -->
<!-- List with single Selection -->
<!-- --------------------------------------------------- -->
<mat-card class="b-1 shadow-none">
<mat-card-header>
<mat-card-title>List with single Selection</mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<mat-selection-list #shoes2 [multiple]="false">
@for(shoe of typesOfShoes; track shoe) {
<mat-list-option [value]="shoe">
{{ shoe }}
</mat-list-option>
}
</mat-selection-list>
<p class="f-w-600 p-16 bg-light-primary rounded">
Option selected:
{{
shoes2.selectedOptions.hasValue()
? shoes2.selectedOptions.selected[0].value
: "None"
}}
</p>
</mat-card-content>
</mat-card>
</div>
<div class="col-12">
<!-- --------------------------------------------------- -->
<!-- List with sections -->
<!-- --------------------------------------------------- -->
<mat-card class="b-1 shadow-none">
<mat-card-header>
<mat-card-title>List with sections</mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<mat-list>
<div mat-subheader class="m-b-16 f-w-600">Folders</div>
@for(folder of folders; track folder.name) {
<mat-list-item>
<mat-icon matListItemIcon>folder</mat-icon>
<div matListItemTitle class="f-w-600">
{{ folder.name }}
</div>
<div matListItemLine class="f-s-14 ">
{{ folder.updated | date }}
</div>
</mat-list-item>
}
<mat-divider></mat-divider>
<div mat-subheader class="m-y-16 f-w-600">Notes</div>
@for(note of notes; track note.name) {
<mat-list-item>
<mat-icon matListItemIcon>note</mat-icon>
<div matListItemTitle class="f-w-600">
{{ note.name }}
</div>
<div matListItemLine class="f-s-14 ">
{{ note.updated | date }}
</div>
</mat-list-item>
}
</mat-list>
</mat-card-content>
</mat-card>
</div>
</div>
</mat-card-content>
</mat-card>

View File

@@ -0,0 +1,48 @@
import { Component } from '@angular/core';
import { MatCardModule } from '@angular/material/card';
import { MatListModule } from '@angular/material/list';
import {MatIconModule} from '@angular/material/icon';
import {DatePipe} from '@angular/common';
import { MaterialModule } from 'src/app/material.module';
export interface Section {
name: string;
updated: Date;
}
@Component({
selector: 'app-lists',
imports: [MatListModule, MatCardModule, DatePipe,MatIconModule, MaterialModule ],
templateUrl: './lists.component.html',
})
export class AppListsComponent {
constructor() {}
typesOfShoes: string[] = ['Loafers', 'Sneakers'];
folders: Section[] = [
{
name: 'Photos',
updated: new Date('1/1/25'),
},
{
name: 'Recipes',
updated: new Date('1/17/25'),
},
{
name: 'Work',
updated: new Date('1/28/25'),
},
];
notes: Section[] = [
{
name: 'Vacation Itinerary',
updated: new Date('2/20/25'),
},
{
name: 'Kitchen Remodel',
updated: new Date('1/18/25'),
},
];
}

View File

@@ -0,0 +1,166 @@
<mat-card class="cardWithShadow theme-card">
<mat-card-header>
<mat-card-title class="m-b-0">Menu</mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<div class="row">
<div class="col-sm-6 col-lg-4">
<mat-card class="b-1 shadow-none">
<mat-card-header>
<mat-card-title>Basic</mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<button mat-flat-button color="primary" class="m-t-8" [matMenuTriggerFor]="menu">
Menu
</button>
<mat-menu #menu="matMenu" class="cardWithShadow">
<button mat-menu-item>Item 1</button>
<button mat-menu-item>Item 2</button>
</mat-menu>
</mat-card-content>
</mat-card>
</div>
<div class="col-sm-6 col-lg-4">
<mat-card class="b-1 shadow-none">
<mat-card-header>
<mat-card-title>with Icons</mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<button mat-icon-button [matMenuTriggerFor]="menu" aria-label="Example icon-button with a menu">
<mat-icon>
<i-tabler name="dots" class="icon-20"></i-tabler>
</mat-icon>
</button>
<mat-menu #menu="matMenu" class="cardWithShadow">
<button mat-menu-item>
<mat-icon>dialpad</mat-icon>
<span>Redial</span>
</button>
<button mat-menu-item disabled>
<mat-icon>voicemail</mat-icon>
<span>Check voice mail</span>
</button>
<button mat-menu-item>
<mat-icon>notifications_off</mat-icon>
<span>Disable alerts</span>
</button>
</mat-menu>
</mat-card-content>
</mat-card>
</div>
<div class="col-sm-6 col-lg-4">
<mat-card class="b-1 shadow-none">
<mat-card-header>
<mat-card-title>Nested Menu</mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<button mat-flat-button color="primary" [matMenuTriggerFor]="animals" class="m-t-8">
Animal index
</button>
<mat-menu class="cardWithShadow" #animals="matMenu">
<button mat-menu-item [matMenuTriggerFor]="vertebrates">
Vertebrates
</button>
<button mat-menu-item [matMenuTriggerFor]="invertebrates">
Invertebrates
</button>
</mat-menu>
<mat-menu class="cardWithShadow" #vertebrates="matMenu">
<button mat-menu-item [matMenuTriggerFor]="fish">Fishes</button>
<button mat-menu-item [matMenuTriggerFor]="amphibians">
Amphibians
</button>
<button mat-menu-item [matMenuTriggerFor]="reptiles">
Reptiles
</button>
<button mat-menu-item>Birds</button>
<button mat-menu-item>Mammals</button>
</mat-menu>
<mat-menu class="cardWithShadow" #invertebrates="matMenu">
<button mat-menu-item>Insects</button>
<button mat-menu-item>Molluscs</button>
<button mat-menu-item>Crustaceans</button>
<button mat-menu-item>Corals</button>
<button mat-menu-item>Arachnids</button>
<button mat-menu-item>Velvet worms</button>
<button mat-menu-item>Horseshoe crabs</button>
</mat-menu>
<mat-menu class="cardWithShadow" #fish="matMenu">
<button mat-menu-item>Baikal oilfish</button>
<button mat-menu-item>Bala shark</button>
<button mat-menu-item>Ballan wrasse</button>
<button mat-menu-item>Bamboo shark</button>
<button mat-menu-item>Banded killifish</button>
</mat-menu>
<mat-menu class="cardWithShadow" #amphibians="matMenu">
<button mat-menu-item>Sonoran desert toad</button>
<button mat-menu-item>Western toad</button>
<button mat-menu-item>Arroyo toad</button>
<button mat-menu-item>Yosemite toad</button>
</mat-menu>
<mat-menu class="cardWithShadow" #reptiles="matMenu">
<button mat-menu-item>Banded Day Gecko</button>
<button mat-menu-item>Banded Gila Monster</button>
<button mat-menu-item>Black Tree Monitor</button>
<button mat-menu-item>Blue Spiny Lizard</button>
<button mat-menu-item disabled>Velociraptor</button>
</mat-menu>
</mat-card-content>
</mat-card>
</div>
<div class="col-12">
<mat-card class="b-1 shadow-none">
<mat-card-header>
<mat-card-title>Positions</mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<div class="row">
<div class="col-sm-3">
<button mat-flat-button color="primary" class="w-100" [matMenuTriggerFor]="aboveMenu">
Above
</button>
<mat-menu class="cardWithShadow" #aboveMenu="matMenu" yPosition="above">
<button mat-menu-item>Item 1</button>
<button mat-menu-item>Item 2</button>
</mat-menu>
</div>
<div class="col-sm-3">
<button mat-flat-button color="accent" class="w-100" [matMenuTriggerFor]="belowMenu">
Below
</button>
<mat-menu class="cardWithShadow" #belowMenu="matMenu" yPosition="below">
<button mat-menu-item>Item 1</button>
<button mat-menu-item>Item 2</button>
</mat-menu>
</div>
<div class="col-sm-3">
<button mat-flat-button color="warn" class="w-100" [matMenuTriggerFor]="beforeMenu">
Before
</button>
<mat-menu class="cardWithShadow" #beforeMenu="matMenu" xPosition="before">
<button mat-menu-item>Item 1</button>
<button mat-menu-item>Item 2</button>
</mat-menu>
</div>
<div class="col-sm-3">
<button mat-flat-button color="primary" class="w-100" [matMenuTriggerFor]="afterMenu">
After
</button>
<mat-menu class="cardWithShadow" #afterMenu="matMenu" xPosition="after">
<button mat-menu-item>Item 1</button>
<button mat-menu-item>Item 2</button>
</mat-menu>
</div>
</div>
</mat-card-content>
</mat-card>
</div>
</div>
</mat-card-content>
</mat-card>

View File

@@ -0,0 +1,15 @@
import { Component } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { TablerIconsModule } from 'angular-tabler-icons';
@Component({
selector: 'app-menu',
imports: [MatCardModule, MatMenuModule, MatIconModule, TablerIconsModule, MatButtonModule],
templateUrl: './menu.component.html',
})
export class AppMenuComponent {
constructor() {}
}

View File

@@ -0,0 +1,102 @@
<mat-card class="cardWithShadow">
<mat-card-content>
<mat-card-title>Table</mat-card-title>
<div class="table-responsive">
<table mat-table [dataSource]="dataSource1" class="w-100">
<!-- Position Column -->
<ng-container matColumnDef="assigned">
<th mat-header-cell *matHeaderCellDef class="f-w-600 f-s-14 p-l-0">
Product
</th>
<td mat-cell *matCellDef="let element" class="p-l-0">
<div class="d-flex align-items-center">
<img [src]="element.imagePath" alt="users" width="60" class="rounded" />
<div class="m-l-16">
<h6 class="f-s-14 f-w-600">
{{ element.uname }}
</h6>
</div>
</div>
</td>
</ng-container>
<!-- Name Column -->
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef class="f-w-600 f-s-14">
Payment
</th>
<td mat-cell *matCellDef="let element">
@if(element.budget >= 160) {
<h6 class=" f-s-16 m-b-4">
<span class="text-dark f-w-600">${{ element.budget }} </span>/ 499
</h6>
<span class="f-s-14 f-w-500 d-block m-b-4">Full paid</span>
<mat-progress-bar mode="determinate" value="80" color="primary"></mat-progress-bar>
} @else if(element.budget > 119) {
<h6 class=" f-s-16 m-b-4">
<span class="text-dark f-w-600">${{ element.budget }} </span>/ 499
</h6>
<span class="f-s-14 f-w-500 d-block m-b-4">Partially paid</span>
<mat-progress-bar mode="determinate" class="mat-error" value="35" color="accent"></mat-progress-bar>
} @else if(element.budget < 100) { <h6 class=" f-s-16 m-b-4">
<span class="text-dark f-w-600">${{ element.budget }} </span>/ 499
</h6>
<span class="f-s-14 f-w-500 d-block m-b-4">Cancelled</span>
<mat-progress-bar mode="determinate" class="mat-warning" value="50" color="warn"></mat-progress-bar>
}
</td>
</ng-container>
<!-- Weight Column -->
<ng-container matColumnDef="priority">
<th mat-header-cell *matHeaderCellDef class="f-w-600 f-s-14">
Status
</th>
<td mat-cell *matCellDef="let element">
@if(element.priority == 'cancelled') {
<span class="bg-light-warning text-warning rounded f-w-600 p-6 p-y-4 f-s-12">
{{ element.priority | titlecase }}
</span>
} @if(element.priority == 'rejected') {
<span class="bg-light-error text-error rounded f-w-600 p-6 p-y-4 f-s-12">
{{ element.priority | titlecase }}
</span>
} @if(element.priority == 'confirmed') {
<span class="bg-light-success text-success rounded f-w-600 p-6 p-y-4 f-s-12">
{{ element.priority | titlecase }}
</span>
}
</td>
</ng-container>
<!-- Symbol Column -->
<ng-container matColumnDef="budget">
<th mat-header-cell *matHeaderCellDef class="f-w-600 f-s-14"></th>
<td mat-cell *matCellDef="let element">
<button mat-icon-button [matMenuTriggerFor]="menu" aria-label="Example icon-button with a menu">
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #menu="matMenu">
<button mat-menu-item>
<mat-icon>add</mat-icon>
<span>Add</span>
</button>
<button mat-menu-item>
<mat-icon>edit</mat-icon>
<span>Edit</span>
</button>
<button mat-menu-item>
<mat-icon>delete</mat-icon>
<span>Delete</span>
</button>
</mat-menu>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns1"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns1"></tr>
</table>
</div>
</mat-card-content>
</mat-card>

View File

@@ -0,0 +1,67 @@
import { CommonModule } from '@angular/common';
import { Component } from '@angular/core';
import { MatCardModule } from '@angular/material/card';
import { MatTableModule } from '@angular/material/table';
import { MaterialModule } from 'src/app/material.module';
import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { MatButtonModule } from '@angular/material/button';
// table 1
export interface productsData {
id: number;
imagePath: string;
uname: string;
budget: number;
priority: string;
}
const PRODUCT_DATA: productsData[] = [
{
id: 1,
imagePath: 'assets/images/products/product-1.png',
uname: 'iPhone 13 pro max-Pacific Blue-128GB storage',
budget: 180,
priority: 'confirmed',
},
{
id: 2,
imagePath: 'assets/images/products/product-2.png',
uname: 'Apple MacBook Pro 13 inch-M1-8/256GB-space',
budget: 90,
priority: 'cancelled',
},
{
id: 3,
imagePath: 'assets/images/products/product-3.png',
uname: 'PlayStation 5 DualSense Wireless Controller',
budget: 120,
priority: 'rejected',
},
{
id: 4,
imagePath: 'assets/images/products/product-4.png',
uname: 'Amazon Basics Mesh, Mid-Back, Swivel Office',
budget: 160,
priority: 'confirmed',
},
];
@Component({
selector: 'app-tables',
imports: [
MatTableModule,
CommonModule,
MatCardModule,
MaterialModule,
MatIconModule,
MatMenuModule,
MatButtonModule,
],
templateUrl: './tables.component.html',
})
export class AppTablesComponent {
// table 1
displayedColumns1: string[] = ['assigned', 'name', 'priority', 'budget'];
dataSource1 = PRODUCT_DATA;
}

View File

@@ -0,0 +1,128 @@
<mat-card class="cardWithShadow theme-card">
<mat-card-header>
<mat-card-title class="m-b-0">Tooltips</mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<div class="row">
<div class="col-lg-4 col-sm-6">
<mat-card class="b-1 shadow-none">
<mat-card-header>
<mat-card-title>Basic</mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<button mat-flat-button color="primary" matTooltip="Info about the action">
Button
</button>
</mat-card-content>
</mat-card>
</div>
<div class="col-lg-4 col-sm-6">
<mat-card class="b-1 shadow-none">
<mat-card-header>
<mat-card-title>Uppercase</mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<button mat-flat-button color="primary" matTooltip="Info about the action" matTooltipClass="text-uppercase">
Button
</button>
</mat-card-content>
</mat-card>
</div>
<div class="col-lg-4 col-sm-6">
<mat-card class="b-1 shadow-none">
<mat-card-header>
<mat-card-title>Disabled on click</mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<button mat-flat-button color="primary" matTooltip="Info about the action"
[matTooltipDisabled]="disabled.value" class="m-r-8">
Action
</button>
<mat-checkbox [formControl]="disabled" class="example-disabled-checkbox">
Tooltip disabled
</mat-checkbox>
</mat-card-content>
</mat-card>
</div>
<div class="col-lg-6">
<mat-card class="b-1 shadow-none">
<mat-card-header>
<mat-card-title>Position</mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<button mat-flat-button color="primary" #tooltip="matTooltip" matTooltip="Info about the action"
matTooltipPosition="below" matTooltipHideDelay="100000">
Below
</button>
<button mat-flat-button color="accent" #tooltip="matTooltip" matTooltip="Info about the action"
matTooltipPosition="above" class="m-l-8" matTooltipHideDelay="100000">
Above
</button>
<button mat-flat-button color="warn" #tooltip="matTooltip" matTooltip="Info about the action"
matTooltipPosition="left" class="m-l-8" matTooltipHideDelay="100000">
Left
</button>
<button mat-flat-button color="primary" #tooltip="matTooltip" matTooltip="Info about the action"
matTooltipPosition="right" class="m-l-8" matTooltipHideDelay="100000">
Right
</button>
</mat-card-content>
</mat-card>
</div>
<div class="col-lg-6">
<mat-card class="b-1 shadow-none">
<mat-card-header>
<mat-card-title>Show and Hide</mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<div class="row">
<div class="col-sm-4">
<mat-form-field class="w-100" appearance="outline">
<mat-label>Show delay</mat-label>
<input matInput type="number" [formControl]="showDelay" />
<mat-hint>milliseconds</mat-hint>
</mat-form-field>
</div>
<div class="col-sm-4">
<mat-form-field class="w-100" appearance="outline">
<mat-label>Hide delay</mat-label>
<input matInput type="number" [formControl]="hideDelay2" />
<mat-hint>milliseconds</mat-hint>
</mat-form-field>
</div>
<div class="col-sm-4">
<button mat-flat-button color="primary" matTooltip="Info about the action"
[matTooltipShowDelay]="showDelay.value" [matTooltipHideDelay]="hideDelay2.value">
Action
</button>
</div>
</div>
</mat-card-content>
</mat-card>
</div>
<div class="col-lg-4 col-sm-6">
<mat-card class="b-1 shadow-none">
<mat-card-header>
<mat-card-title>Change Message</mat-card-title>
</mat-card-header>
<mat-card-content class="b-t-1">
<mat-form-field class="w-100" appearance="outline">
<mat-label>Tooltip message</mat-label>
<input matInput [formControl]="message" />
</mat-form-field>
<button mat-flat-button color="primary" [matTooltip]="message.value || ''"
aria-label="Button that displays a tooltip with a custom message">
Action
</button>
</mat-card-content>
</mat-card>
</div>
</div>
</mat-card-content>
</mat-card>

View File

@@ -0,0 +1,33 @@
import { Component } from '@angular/core';
import {FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms';
import {MatTooltipModule} from '@angular/material/tooltip';
import {MatButtonModule} from '@angular/material/button';
import {MatSelectModule} from '@angular/material/select';
import {MatFormFieldModule} from '@angular/material/form-field';
import { MatCardModule } from '@angular/material/card';
import { MatInputModule } from '@angular/material/input';
import { MatCheckboxModule } from '@angular/material/checkbox';
@Component({
selector: 'app-tooltips',
imports: [
MatFormFieldModule,
MatSelectModule,
FormsModule,
ReactiveFormsModule,
MatButtonModule,
MatTooltipModule, MatCardModule, MatInputModule, MatCheckboxModule
],
templateUrl: './tooltips.component.html',
})
export class AppTooltipsComponent {
// disabled
disabled = new FormControl(false);
// show and hide
showDelay = new FormControl(1000);
hideDelay2 = new FormControl(2000);
// change message
message = new FormControl('Info about the action');
}

View File

@@ -0,0 +1,46 @@
import { Routes } from '@angular/router';
// ui
import { AppBadgeComponent } from './badge/badge.component';
import { AppChipsComponent } from './chips/chips.component';
import { AppListsComponent } from './lists/lists.component';
import { AppMenuComponent } from './menu/menu.component';
import { AppTooltipsComponent } from './tooltips/tooltips.component';
import { AppFormsComponent } from './forms/forms.component';
import { AppTablesComponent } from './tables/tables.component';
export const UiComponentsRoutes: Routes = [
{
path: '',
children: [
{
path: 'badge',
component: AppBadgeComponent,
},
{
path: 'chips',
component: AppChipsComponent,
},
{
path: 'lists',
component: AppListsComponent,
},
{
path: 'menu',
component: AppMenuComponent,
},
{
path: 'tooltips',
component: AppTooltipsComponent,
},
{
path: 'forms',
component: AppFormsComponent,
},
{
path: 'tables',
component: AppTablesComponent,
},
],
},
];

View File

@@ -0,0 +1,18 @@
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({ name: 'appFilter', standalone: true, pure: true })
export class FilterPipe implements PipeTransform {
transform(items: any[], searchText: string): any[] {
if (!items) {
return [];
}
if (!searchText) {
return items;
}
searchText = searchText.toLocaleLowerCase();
return items.filter((it) => {
return it.displayName.toLocaleLowerCase().includes(searchText);
});
}
}

View File

@@ -0,0 +1,21 @@
import { Injectable, signal } from '@angular/core';
import { AppSettings, defaults } from '../config';
@Injectable({
providedIn: 'root',
})
export class CoreService {
private optionsSignal = signal<AppSettings>(defaults);
getOptions() {
return this.optionsSignal();
}
setOptions(options: Partial<AppSettings>) {
this.optionsSignal.update((current) => ({
...current,
...options,
}));
}
}

View File

@@ -0,0 +1,17 @@
import { Injectable, signal } from '@angular/core';
import { Event, NavigationEnd, Router } from '@angular/router';
@Injectable({ providedIn: 'root' })
export class NavService {
showClass: any = false;
public currentUrl = signal<string | undefined>(undefined);
constructor(private router: Router) {
this.router.events.subscribe((event: Event) => {
if (event instanceof NavigationEnd) {
this.currentUrl.set(event.urlAfterRedirects);
}
});
}
}

View File

View File

@@ -0,0 +1,7 @@
{
"Starter": "Menüebene",
"Menu Level": "Menüebene",
"Menu 1": "Menü 1",
"Menu 2": "Menü 2",
"Disabled": "Behinderte"
}

View File

@@ -0,0 +1,7 @@
{
"Starter": "Starter",
"Menu Level": "Menu Level",
"Menu 1": "Menu 1",
"Menu 2": "Menu 2",
"Disabled": "Disabled"
}

View File

@@ -0,0 +1,7 @@
{
"Starter": "Analítica",
"Menu Level": "Nível do menu",
"Menu 1": "Menu 1",
"Menu 2": "Menu 2",
"Disabled": "Desabilitada"
}

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