Refactor HTML and configuration files for improved structure and consistency

- Updated videos.html to enhance readability and maintainability.
- Refactored webpack.config.js for better organization and clarity.
- Cleaned up TypeScript configuration files (tsconfig.app.json, tsconfig.json, tsconfig.spec.json) for consistency in formatting.
- Adjusted docker-compose.yaml for improved formatting and readability.
This commit is contained in:
Marek Lesko
2025-08-05 06:35:56 +00:00
parent 83ca026a55
commit 02116aa3df
312 changed files with 45638 additions and 45628 deletions

View File

@@ -1,20 +1,19 @@
FROM mcr.microsoft.com/devcontainers/dotnet:1-8.0-bookworm FROM mcr.microsoft.com/devcontainers/dotnet:1-8.0-bookworm
# Install SQL Tools: SQLPackage and sqlcmd # Install SQL Tools: SQLPackage and sqlcmd
COPY mssql/installSQLtools.sh installSQLtools.sh COPY mssql/installSQLtools.sh installSQLtools.sh
RUN bash ./installSQLtools.sh \ RUN bash ./installSQLtools.sh && apt-get clean -y && rm -rf /var/lib/apt/lists/* /tmp/library-scripts
&& apt-get clean -y && rm -rf /var/lib/apt/lists/* /tmp/library-scripts
# RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
# RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \ # echo "deb http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google.list && \
# echo "deb http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google.list && \ # apt-get update && apt-get install -y google-chrome-stable xvfb
# apt-get update && apt-get install -y google-chrome-stable xvfb # [Optional] Uncomment this section to install additional OS packages.
# [Optional] Uncomment this section to install additional OS packages. # RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ # && apt-get -y install --no-install-recommends <your-package-list-here>
# && apt-get -y install --no-install-recommends <your-package-list-here>
ENV ASPNETCORE_HTTP_PORTS=5000
ENV ASPNETCORE_HTTP_PORTS=5000
EXPOSE 4200
EXPOSE 4200 # [Optional] Uncomment this line to install global node packages.
# [Optional] Uncomment this line to install global node packages. RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && nvm install --lts && nvm use --lts && npm install -g typescript" 2>&1
RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && nvm install --lts && nvm use --lts && npm install -g typescript" 2>&1 # RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1
# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1

View File

@@ -1,59 +1,59 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the // For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/dotnet-mssql // README at: https://github.com/devcontainers/templates/tree/main/src/dotnet-mssql
{ {
"name": ".NET (C#), Node.js (TypeScript) & MS SQL", "name": ".NET (C#), Node.js (TypeScript) & MS SQL",
"dockerComposeFile": "docker-compose.yml", "dockerComposeFile": "docker-compose.yml",
"service": "app", "service": "app",
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
// Features to add to the dev container. More info: https://containers.dev/features. // Features to add to the dev container. More info: https://containers.dev/features.
// "features": {}, // "features": {},
// Configure tool-specific properties. // Configure tool-specific properties.
"customizations": { "customizations": {
// Configure properties specific to VS Code. // Configure properties specific to VS Code.
"vscode": { "vscode": {
// Set *default* container specific settings.json values on container create. // Set *default* container specific settings.json values on container create.
"settings": { "settings": {
"mssql.connections": [ "mssql.connections": [
{ {
"server": "localhost,1433", "server": "localhost,1433",
"database": "", "database": "",
"authenticationType": "SqlLogin", "authenticationType": "SqlLogin",
"user": "sa", "user": "sa",
"password": "P@ssw0rd", "password": "P@ssw0rd",
"emptyPasswordInput": false, "emptyPasswordInput": false,
"savePassword": false, "savePassword": false,
"profileName": "mssql-container" "profileName": "mssql-container"
} }
] ]
}, },
// Add the IDs of extensions you want installed when the container is created. // Add the IDs of extensions you want installed when the container is created.
"extensions": [ "extensions": [
"ms-dotnettools.csharp", "ms-dotnettools.csharp",
"ms-mssql.mssql" "ms-mssql.mssql"
] ]
} }
}, },
// Use 'forwardPorts' to make a list of ports inside the container available locally. // Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [ "forwardPorts": [
4200, 4200,
5000, 5000,
5001, 5001,
1433 1433
], ],
"portsAttributes": { "portsAttributes": {
"5001": { "5001": {
"protocol": "https" "protocol": "https"
}, },
"1433": { "1433": {
"protocol": "tcp" "protocol": "tcp"
} }
}, },
// postCreateCommand.sh parameters: $1=SA password, $2=dacpac path, $3=sql script(s) path // postCreateCommand.sh parameters: $1=SA password, $2=dacpac path, $3=sql script(s) path
"containerEnv": { "containerEnv": {
"SA_PASSWORD": "P@ssw0rd", "SA_PASSWORD": "P@ssw0rd",
"ACCEPT_EULA": "Y" "ACCEPT_EULA": "Y"
}, },
"postCreateCommand": "bash .devcontainer/mssql/postCreateCommand.sh 'P@ssw0rd' './bin/Debug/' './.devcontainer/mssql/'" "postCreateCommand": "bash .devcontainer/mssql/postCreateCommand.sh 'P@ssw0rd' './bin/Debug/' './.devcontainer/mssql/'"
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root" // "remoteUser": "root"
} }

View File

@@ -1,34 +1,34 @@
version: '3' version: '3'
services: services:
app: app:
build: build:
context: . context: .
dockerfile: Dockerfile dockerfile: Dockerfile
volumes: volumes:
- ../..:/workspaces:cached - ../..:/workspaces:cached
# Overrides default command so things don't shut down after the process ends. # Overrides default command so things don't shut down after the process ends.
command: sleep infinity command: sleep infinity
ports: ports:
- "4200:4200" - "4200:4200"
# Runs app on the same network as the database container, allows "forwardPorts" in devcontainer.json function. # Runs app on the same network as the database container, allows "forwardPorts" in devcontainer.json function.
network_mode: host network_mode: host
# Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. # Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
# user: root # user: root
# Use "forwardPorts" in **devcontainer.json** to forward an app port locally. # Use "forwardPorts" in **devcontainer.json** to forward an app port locally.
# (Adding the "ports" property to this file will not forward from a Codespace.) # (Adding the "ports" property to this file will not forward from a Codespace.)
db: db:
image: mcr.microsoft.com/mssql/server:2019-latest image: mcr.microsoft.com/mssql/server:2019-latest
restart: unless-stopped restart: unless-stopped
network_mode: host network_mode: host
environment: environment:
SA_PASSWORD: P@ssw0rd SA_PASSWORD: P@ssw0rd
ACCEPT_EULA: Y ACCEPT_EULA: Y
# Add "forwardPorts": ["db:1433"] to **devcontainer.json** to forward MSSQL locally. # Add "forwardPorts": ["db:1433"] to **devcontainer.json** to forward MSSQL locally.
# (Adding the "ports" property to this file will not forward from a Codespace.) # (Adding the "ports" property to this file will not forward from a Codespace.)

View File

@@ -0,0 +1,64 @@
#!/bin/bash
dacpac="false"
sqlfiles="false"
SApassword=$1
dacpath=$2
sqlpath=$3
echo "SELECT * FROM SYS.DATABASES" | dd of=testsqlconnection.sql
for i in {1..60};
do
/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P $SApassword -d master -i testsqlconnection.sql > /dev/null
if [ $? -eq 0 ]
then
echo "SQL server ready"
break
else
echo "Not ready yet..."
sleep 1
fi
done
rm testsqlconnection.sql
for f in $dacpath/*
do
if [ $f == $dacpath/*".dacpac" ]
then
dacpac="true"
echo "Found dacpac $f"
fi
done
for f in $sqlpath/*
do
if [ $f == $sqlpath/*".sql" ]
then
sqlfiles="true"
echo "Found SQL file $f"
fi
done
if [ $sqlfiles == "true" ]
then
for f in $sqlpath/*
do
if [ $f == $sqlpath/*".sql" ]
then
echo "Executing $f"
/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P $SApassword -d master -i $f
fi
done
fi
if [ $dacpac == "true" ]
then
for f in $dacpath/*
do
if [ $f == $dacpath/*".dacpac" ]
then
dbname=$(basename $f ".dacpac")
echo "Deploying dacpac $f"
/opt/sqlpackage/sqlpackage /Action:Publish /SourceFile:$f /TargetServerName:localhost /TargetDatabaseName:$dbname /TargetUser:sa /TargetPassword:$SApassword
fi
done
fi

View File

@@ -5,60 +5,9 @@ SApassword=$1
dacpath=$2 dacpath=$2
sqlpath=$3 sqlpath=$3
echo "SELECT * FROM SYS.DATABASES" | dd of=testsqlconnection.sql cd Api
for i in {1..60}; dotnet restore ./Api.csproj
do dotnet build ./Api.csproj
/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P $SApassword -d master -i testsqlconnection.sql > /dev/null dotnet tool install --global dotnet-ef --version 8.*
if [ $? -eq 0 ] export PATH="$PATH:/root/.dotnet/tools"
then dotnet-ef database update --project ./Api.csproj --startup-project ./Api.csproj
echo "SQL server ready"
break
else
echo "Not ready yet..."
sleep 1
fi
done
rm testsqlconnection.sql
for f in $dacpath/*
do
if [ $f == $dacpath/*".dacpac" ]
then
dacpac="true"
echo "Found dacpac $f"
fi
done
for f in $sqlpath/*
do
if [ $f == $sqlpath/*".sql" ]
then
sqlfiles="true"
echo "Found SQL file $f"
fi
done
if [ $sqlfiles == "true" ]
then
for f in $sqlpath/*
do
if [ $f == $sqlpath/*".sql" ]
then
echo "Executing $f"
/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P $SApassword -d master -i $f
fi
done
fi
if [ $dacpac == "true" ]
then
for f in $dacpath/*
do
if [ $f == $dacpath/*".dacpac" ]
then
dbname=$(basename $f ".dacpac")
echo "Deploying dacpac $f"
/opt/sqlpackage/sqlpackage /Action:Publish /SourceFile:$f /TargetServerName:localhost /TargetDatabaseName:$dbname /TargetUser:sa /TargetPassword:$SApassword
fi
done
fi

View File

@@ -1,2 +0,0 @@
CREATE DATABASE ApplicationDB;
GO

View File

@@ -1,12 +1,12 @@
# To get started with Dependabot version updates, you'll need to specify which # To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located. # package ecosystems to update and where the package manifests are located.
# Please see the documentation for more information: # Please see the documentation for more information:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
# https://containers.dev/guide/dependabot # https://containers.dev/guide/dependabot
version: 2 version: 2
updates: updates:
- package-ecosystem: "devcontainers" - package-ecosystem: "devcontainers"
directory: "/" directory: "/"
schedule: schedule:
interval: weekly interval: weekly

View File

@@ -1,78 +1,78 @@
stages: # Define the stages of the pipeline. stages: # Define the stages of the pipeline.
- build - build
#- test #- test
- release - release
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 - 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:
- main - main
docker-build: docker-build:
stage: build stage: build
image: docker:latest image: docker:latest
tags: tags:
- shared - shared
services: services:
- name: docker:dind - name: docker:dind
alias: docker alias: docker
variables: variables:
DOCKER_DRIVER: overlay2 DOCKER_DRIVER: overlay2
DOCKER_HOST: tcp://docker:2375 DOCKER_HOST: tcp://docker:2375
DOCKER_TLS_CERTDIR: "" DOCKER_TLS_CERTDIR: ""
before_script: before_script:
- docker info - docker info
script: script:
- 'sed -i "s|\"apiEndpoint\": \"[^\"]*\"|\"apiEndpoint\": \"https\:\/\/""$PUBLIC_WEB_URL""\"|" Web/public/config.json' - 'sed -i "s|\"apiEndpoint\": \"[^\"]*\"|\"apiEndpoint\": \"https\:\/\/""$PUBLIC_WEB_URL""\"|" Web/public/config.json'
- 'sed -i "s|\"AllowedHosts\": \"[^\"]*\"|\"AllowedHosts\": \"$PUBLIC_WEB_URL\"|" Api/appsettings.json' - 'sed -i "s|\"AllowedHosts\": \"[^\"]*\"|\"AllowedHosts\": \"$PUBLIC_WEB_URL\"|" Api/appsettings.json'
- 'sed -i "s|\"CorsOrigins\": \"[^\"]*\"|\"CorsOrigins\": \"https\:\/\/""$PUBLIC_WEB_URL""\"|" Api/appsettings.json' - 'sed -i "s|\"CorsOrigins\": \"[^\"]*\"|\"CorsOrigins\": \"https\:\/\/""$PUBLIC_WEB_URL""\"|" Api/appsettings.json'
- docker build -t $CI_REGISTRY_IMAGE:latest -t $CI_REGISTRY_IMAGE:${CI_PIPELINE_IID} -f Dockerfile . - docker build -t $CI_REGISTRY_IMAGE:latest -t $CI_REGISTRY_IMAGE:${CI_PIPELINE_IID} -f Dockerfile .
- echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY - echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY
- docker push $CI_REGISTRY_IMAGE:latest - docker push $CI_REGISTRY_IMAGE:latest
- docker push $CI_REGISTRY_IMAGE:${CI_PIPELINE_IID} - docker push $CI_REGISTRY_IMAGE:${CI_PIPELINE_IID}
only: only:
- dev - dev
- main - main
docker-deploy: docker-deploy:
stage: release stage: release
tags: tags:
- production - production
- shell - shell
script: script:
- echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY - echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY
- cd deployment - cd deployment
- docker compose pull - docker compose pull
- docker compose -f docker-compose.yaml up -d - docker compose -f docker-compose.yaml up -d
- docker image prune -f - docker image prune -f
only: only:
- dev - dev
- main - main
update_db: update_db:
image: mcr.microsoft.com/dotnet/sdk:8.0 image: mcr.microsoft.com/dotnet/sdk:8.0
stage: release stage: release
needs: ["docker-deploy"] needs: ["docker-deploy"]
script: script:
- cd Api - cd Api
- dotnet restore ./Api.csproj - dotnet restore ./Api.csproj
- dotnet build ./Api.csproj - dotnet build ./Api.csproj
- dotnet tool install --global dotnet-ef --version 8.* - dotnet tool install --global dotnet-ef --version 8.*
- export PATH="$PATH:/root/.dotnet/tools" - export PATH="$PATH:/root/.dotnet/tools"
- dotnet-ef database update --project ./Api.csproj --startup-project ./Api.csproj - dotnet-ef database update --project ./Api.csproj --startup-project ./Api.csproj
only: only:
- dev - dev
- main - main
tags: tags:
- production - production
- docker - docker
variables: variables:
ConnectionStrings__DefaultConnection: "Server=localhost;Database=CentrumDb;User=sa;Password=$DB_PASSWORD;TrustServerCertificate=True;" ConnectionStrings__DefaultConnection: "Server=localhost;Database=CentrumDb;User=sa;Password=$DB_PASSWORD;TrustServerCertificate=True;"

View File

@@ -1,2 +1,2 @@
coreDump: coreDump:
enabled: false enabled: false

View File

@@ -1,37 +1,37 @@
tasks: tasks:
hello: hello:
name: Hello World name: Hello World
command: | command: |
echo "Hello, World!" echo "Hello, World!"
triggeredBy: triggeredBy:
- manual - manual
# - postEnvironmentStart # - postEnvironmentStart
# - postDevcontainerStart # - postDevcontainerStart
services: services:
example-service: example-service:
name: Example Service name: Example Service
description: Example service simulating a backend description: Example service simulating a backend
commands: commands:
start: | start: |
echo "Starting backend service..." echo "Starting backend service..."
touch /tmp/backend.started touch /tmp/backend.started
while true; do while true; do
sleep 1 sleep 1
date date
done done
ready: | ready: |
if [ -f /tmp/backend.started ]; then if [ -f /tmp/backend.started ]; then
echo "Backend service is ready" echo "Backend service is ready"
exit 0 exit 0
else else
echo "Backend service is not ready" echo "Backend service is not ready"
exit 1 exit 1
fi fi
# stop: | # stop: |
# echo "Stopping backend service..." # echo "Stopping backend service..."
# rm /tmp/backend.started # rm /tmp/backend.started
# pkill backend # pkill backend
triggeredBy: triggeredBy:
- postEnvironmentStart - postEnvironmentStart
# - postDevcontainerStart # - postDevcontainerStart

28
.vscode/launch.json vendored
View File

@@ -1,15 +1,15 @@
{ {
// Use IntelliSense to learn about possible attributes. // Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes. // Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{ {
"type": "chrome", "type": "chrome",
"request": "launch", "request": "launch",
"name": "Launch Chrome against localhost", "name": "Launch Chrome against localhost",
"url": "http://localhost:4200", "url": "http://localhost:4200",
"webRoot": "${workspaceFolder}/Web" "webRoot": "${workspaceFolder}/Web"
} }
] ]
} }

80
.vscode/tasks.json vendored
View File

@@ -1,41 +1,41 @@
{ {
"version": "2.0.0", "version": "2.0.0",
"tasks": [ "tasks": [
{ {
"label": "build", "label": "build",
"command": "dotnet", "command": "dotnet",
"type": "process", "type": "process",
"args": [ "args": [
"build", "build",
"${workspaceFolder}/Api/Api.sln", "${workspaceFolder}/Api/Api.sln",
"/property:GenerateFullPaths=true", "/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary;ForceNoAlign" "/consoleloggerparameters:NoSummary;ForceNoAlign"
], ],
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
}, },
{ {
"label": "publish", "label": "publish",
"command": "dotnet", "command": "dotnet",
"type": "process", "type": "process",
"args": [ "args": [
"publish", "publish",
"${workspaceFolder}/Api/Api.sln", "${workspaceFolder}/Api/Api.sln",
"/property:GenerateFullPaths=true", "/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary;ForceNoAlign" "/consoleloggerparameters:NoSummary;ForceNoAlign"
], ],
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
}, },
{ {
"label": "watch", "label": "watch",
"command": "dotnet", "command": "dotnet",
"type": "process", "type": "process",
"args": [ "args": [
"watch", "watch",
"run", "run",
"--project", "--project",
"${workspaceFolder}/Api/Api.sln" "${workspaceFolder}/Api/Api.sln"
], ],
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
} }
] ]
} }

8
Api/.gitignore vendored
View File

@@ -1,5 +1,5 @@
obj/ obj/
bin/ bin/
.vs/ .vs/
build/ build/
**/core **/core

View File

@@ -1,70 +1,70 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Api.Models; using Api.Models;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
namespace Api.Controllers namespace Api.Controllers
{ {
[ApiController] [ApiController]
[Authorize] [Authorize]
[Route("api/product")] [Route("api/product")]
public class ProductController : ControllerBase public class ProductController : ControllerBase
{ {
private readonly AppDbContext _context; private readonly AppDbContext _context;
public ProductController(AppDbContext context) public ProductController(AppDbContext context)
{ {
_context = context; _context = context;
} }
// GET: api/Product // GET: api/Product
[HttpGet] [HttpGet]
public async Task<ActionResult<IEnumerable<Product>>> GetProducts([FromQuery] int? id = null) public async Task<ActionResult<IEnumerable<Product>>> GetProducts([FromQuery] int? id = null)
{ {
if (id.HasValue) if (id.HasValue)
{ {
return await _context.Products return await _context.Products
.Where(p => p.Id == id.Value) .Where(p => p.Id == id.Value)
.ToListAsync(); .ToListAsync();
} }
else else
return await _context.Products.ToListAsync(); return await _context.Products.ToListAsync();
} }
// POST: api/Product // POST: api/Product
[HttpPost] [HttpPost]
public async Task<ActionResult<Product>> PostProduct([FromBody] Product product) public async Task<ActionResult<Product>> PostProduct([FromBody] Product product)
{ {
_context.Products.Add(product); _context.Products.Add(product);
await _context.SaveChangesAsync(); await _context.SaveChangesAsync();
return CreatedAtAction(nameof(GetProducts), new { id = product.Id }, product); return CreatedAtAction(nameof(GetProducts), new { id = product.Id }, product);
} }
// PUT: api/Product/{id} // PUT: api/Product/{id}
[HttpPut("{id}")] [HttpPut("{id}")]
public async Task<IActionResult> PutProduct(int id, [FromBody] Product product) public async Task<IActionResult> PutProduct(int id, [FromBody] Product product)
{ {
if (id != product.Id) if (id != product.Id)
{ {
return BadRequest(); return BadRequest();
} }
_context.Entry(product).State = EntityState.Modified; _context.Entry(product).State = EntityState.Modified;
try try
{ {
await _context.SaveChangesAsync(); await _context.SaveChangesAsync();
} }
catch (DbUpdateConcurrencyException) catch (DbUpdateConcurrencyException)
{ {
if (!await _context.Products.AnyAsync(e => e.Id == id)) if (!await _context.Products.AnyAsync(e => e.Id == id))
{ {
return NotFound(); return NotFound();
} }
else else
{ {
throw; throw;
} }
} }
return NoContent(); return NoContent();
} }
} }
} }

View File

@@ -1,56 +1,56 @@
// <auto-generated /> // <auto-generated />
using Api.Models; using Api.Models;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable #nullable disable
namespace Api.Migrations namespace Api.Migrations
{ {
[DbContext(typeof(AppDbContext))] [DbContext(typeof(AppDbContext))]
[Migration("20250727154636_InitialCreate")] [Migration("20250727154636_InitialCreate")]
partial class InitialCreate partial class InitialCreate
{ {
/// <inheritdoc /> /// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder) protected override void BuildTargetModel(ModelBuilder modelBuilder)
{ {
#pragma warning disable 612, 618 #pragma warning disable 612, 618
modelBuilder modelBuilder
.HasAnnotation("ProductVersion", "9.0.7") .HasAnnotation("ProductVersion", "9.0.7")
.HasAnnotation("Relational:MaxIdentifierLength", 128); .HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("Api.Models.Product", b => modelBuilder.Entity("Api.Models.Product", b =>
{ {
b.Property<int>("Id") b.Property<int>("Id")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("int"); .HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Name") b.Property<string>("Name")
.HasColumnType("nvarchar(max)"); .HasColumnType("nvarchar(max)");
b.Property<decimal>("Price") b.Property<decimal>("Price")
.HasColumnType("decimal(18,2)"); .HasColumnType("decimal(18,2)");
b.HasKey("Id"); b.HasKey("Id");
b.ToTable("Products"); b.ToTable("Products");
b.HasData( b.HasData(
new new
{ {
Id = 1, Id = 1,
Name = "Sample Product", Name = "Sample Product",
Price = 9.99m Price = 9.99m
}); });
}); });
#pragma warning restore 612, 618 #pragma warning restore 612, 618
} }
} }
} }

View File

@@ -1,40 +1,40 @@
using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable #nullable disable
namespace Api.Migrations namespace Api.Migrations
{ {
/// <inheritdoc /> /// <inheritdoc />
public partial class InitialCreate : Migration public partial class InitialCreate : Migration
{ {
/// <inheritdoc /> /// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder) protected override void Up(MigrationBuilder migrationBuilder)
{ {
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
name: "Products", name: "Products",
columns: table => new columns: table => new
{ {
Id = table.Column<int>(type: "int", nullable: false) Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"), .Annotation("SqlServer:Identity", "1, 1"),
Name = table.Column<string>(type: "nvarchar(max)", nullable: true), Name = table.Column<string>(type: "nvarchar(max)", nullable: true),
Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false) Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false)
}, },
constraints: table => constraints: table =>
{ {
table.PrimaryKey("PK_Products", x => x.Id); table.PrimaryKey("PK_Products", x => x.Id);
}); });
migrationBuilder.InsertData( migrationBuilder.InsertData(
table: "Products", table: "Products",
columns: new[] { "Id", "Name", "Price" }, columns: new[] { "Id", "Name", "Price" },
values: new object[] { 1, "Sample Product", 9.99m }); values: new object[] { 1, "Sample Product", 9.99m });
} }
/// <inheritdoc /> /// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder) protected override void Down(MigrationBuilder migrationBuilder)
{ {
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "Products"); name: "Products");
} }
} }
} }

View File

@@ -1,53 +1,53 @@
// <auto-generated /> // <auto-generated />
using Api.Models; using Api.Models;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable #nullable disable
namespace Api.Migrations namespace Api.Migrations
{ {
[DbContext(typeof(AppDbContext))] [DbContext(typeof(AppDbContext))]
partial class AppDbContextModelSnapshot : ModelSnapshot partial class AppDbContextModelSnapshot : ModelSnapshot
{ {
protected override void BuildModel(ModelBuilder modelBuilder) protected override void BuildModel(ModelBuilder modelBuilder)
{ {
#pragma warning disable 612, 618 #pragma warning disable 612, 618
modelBuilder modelBuilder
.HasAnnotation("ProductVersion", "9.0.7") .HasAnnotation("ProductVersion", "9.0.7")
.HasAnnotation("Relational:MaxIdentifierLength", 128); .HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("Api.Models.Product", b => modelBuilder.Entity("Api.Models.Product", b =>
{ {
b.Property<int>("Id") b.Property<int>("Id")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("int"); .HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Name") b.Property<string>("Name")
.HasColumnType("nvarchar(max)"); .HasColumnType("nvarchar(max)");
b.Property<decimal>("Price") b.Property<decimal>("Price")
.HasColumnType("decimal(18,2)"); .HasColumnType("decimal(18,2)");
b.HasKey("Id"); b.HasKey("Id");
b.ToTable("Products"); b.ToTable("Products");
b.HasData( b.HasData(
new new
{ {
Id = 1, Id = 1,
Name = "Sample Product", Name = "Sample Product",
Price = 9.99m Price = 9.99m
}); });
}); });
#pragma warning restore 612, 618 #pragma warning restore 612, 618
} }
} }
} }

View File

@@ -1,27 +1,27 @@
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System.Collections.Generic; using System.Collections.Generic;
namespace Api.Models namespace Api.Models
{ {
public class Product public class Product
{ {
public int Id { get; set; } public int Id { get; set; }
public string? Name { get; set; } public string? Name { get; set; }
public decimal Price { get; set; } public decimal Price { get; set; }
} }
public class AppDbContext : DbContext public class AppDbContext : DbContext
{ {
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { } public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
public DbSet<Product> Products { get; set; } public DbSet<Product> Products { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnModelCreating(ModelBuilder modelBuilder)
{ {
base.OnModelCreating(modelBuilder); base.OnModelCreating(modelBuilder);
// Seed data // Seed data
modelBuilder.Entity<Product>().HasData( modelBuilder.Entity<Product>().HasData(
new Product { Id = 1, Name = "Sample Product", Price = 9.99M } new Product { Id = 1, Name = "Sample Product", Price = 9.99M }
); );
} }
} }
} }

View File

@@ -76,7 +76,7 @@ namespace Api
.AddRewrite(@$"^(?!.*?\b({rewriteString}))^(?!.*?\.\b(jpg|jpeg|png|svg|ttf|woff|woff2|html|js|json|css|ico))", "index.html", false); .AddRewrite(@$"^(?!.*?\b({rewriteString}))^(?!.*?\.\b(jpg|jpeg|png|svg|ttf|woff|woff2|html|js|json|css|ico))", "index.html", false);
app.UseRewriter(rewriteOptions); app.UseRewriter(rewriteOptions);
// Serve static files from the Angular app
if (app.Environment.IsDevelopment()) if (app.Environment.IsDevelopment())
{ {
var currentDirectory = Directory.GetCurrentDirectory(); var currentDirectory = Directory.GetCurrentDirectory();

View File

@@ -1,24 +1,24 @@
# Build Angular Web app # Build Angular Web app
FROM node:24 AS web-build FROM node:24 AS web-build
WORKDIR /app/web WORKDIR /app/web
COPY Web/package*.json ./ COPY Web/package*.json ./
RUN npm install RUN npm install
COPY Web/ ./ COPY Web/ ./
RUN npm run build -- --output-path=dist/Web/browser RUN npm run build -- --output-path=dist/Web/browser
# Build .NET Api app # Build .NET Api app
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS api-build FROM mcr.microsoft.com/dotnet/sdk:8.0 AS api-build
WORKDIR /app/api WORKDIR /app/api
COPY Api/*.csproj ./ COPY Api/*.csproj ./
RUN dotnet restore RUN dotnet restore
COPY Api/ ./ COPY Api/ ./
RUN dotnet publish Api.csproj -c Release -o /app/api/build RUN dotnet publish Api.csproj -c Release -o /app/api/build
# Final runtime image # Final runtime image
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final
WORKDIR /app WORKDIR /app
COPY --from=api-build /app/api/build ./ COPY --from=api-build /app/api/build ./
COPY --from=web-build /app/web/dist/Web/browser/**/* ./wwwroot/ COPY --from=web-build /app/web/dist/Web/browser/**/* ./wwwroot/
ENV ASPNETCORE_URLS=http://+:5000 ENV ASPNETCORE_URLS=http://+:5000
EXPOSE 5000 EXPOSE 5000
ENTRYPOINT ["dotnet", "Api.dll"] ENTRYPOINT ["dotnet", "Api.dll"]

186
README.md
View File

@@ -1,93 +1,93 @@
# Centrum # Centrum
![release](https://gitlab.lesko.me/marek/centrum/-/badges/release.svg) ![release](https://gitlab.lesko.me/marek/centrum/-/badges/release.svg)
[![pipeline status](https://gitlab.lesko.me/marek/centrum/badges/main/pipeline.svg)](https://gitlab.lesko.me/marek/centrum/-/commits/main) [![pipeline status](https://gitlab.lesko.me/marek/centrum/badges/main/pipeline.svg)](https://gitlab.lesko.me/marek/centrum/-/commits/main)
## Getting started ## Getting started
To make it easy for you to get started with GitLab, here's a list of recommended next steps. To make it easy for you to get started with GitLab, here's a list of recommended next steps.
Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)! Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
## Add your files ## Add your files
- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files - [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
- [ ] [Add files using the command line](https://docs.gitlab.com/topics/git/add_files/#add-files-to-a-git-repository) or push an existing Git repository with the following command: - [ ] [Add files using the command line](https://docs.gitlab.com/topics/git/add_files/#add-files-to-a-git-repository) or push an existing Git repository with the following command:
``` ```
cd existing_repo cd existing_repo
git remote add origin https://gitlab.lesko.me/marek/centrum.git git remote add origin https://gitlab.lesko.me/marek/centrum.git
git branch -M main git branch -M main
git push -uf origin main git push -uf origin main
``` ```
## Integrate with your tools ## Integrate with your tools
- [ ] [Set up project integrations](https://gitlab.lesko.me/marek/centrum/-/settings/integrations) - [ ] [Set up project integrations](https://gitlab.lesko.me/marek/centrum/-/settings/integrations)
## Collaborate with your team ## Collaborate with your team
- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/) - [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html) - [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically) - [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/) - [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
- [ ] [Set auto-merge](https://docs.gitlab.com/user/project/merge_requests/auto_merge/) - [ ] [Set auto-merge](https://docs.gitlab.com/user/project/merge_requests/auto_merge/)
## Test and Deploy ## Test and Deploy
Use the built-in continuous integration in GitLab. Use the built-in continuous integration in GitLab.
- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/) - [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/)
- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing (SAST)](https://docs.gitlab.com/ee/user/application_security/sast/) - [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing (SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html) - [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/) - [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html) - [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
*** ***
# Editing this README # Editing this README
When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thanks to [makeareadme.com](https://www.makeareadme.com/) for this template. When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thanks to [makeareadme.com](https://www.makeareadme.com/) for this template.
## Suggestions for a good README ## Suggestions for a good README
Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information. Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
## Name ## Name
Choose a self-explaining name for your project. Choose a self-explaining name for your project.
## Description ## Description
Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors. Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
## Badges ## Badges
On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge. On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
## Visuals ## Visuals
Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method. Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
## Installation ## Installation
Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection. Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
## Usage ## Usage
Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README. Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
## Support ## Support
Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc. Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
## Roadmap ## Roadmap
If you have ideas for releases in the future, it is a good idea to list them in the README. If you have ideas for releases in the future, it is a good idea to list them in the README.
## Contributing ## Contributing
State if you are open to contributions and what your requirements are for accepting them. State if you are open to contributions and what your requirements are for accepting them.
For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self. For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser. You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
## Authors and acknowledgment ## Authors and acknowledgment
Show your appreciation to those who have contributed to the project. Show your appreciation to those who have contributed to the project.
## License ## License
For open source projects, say how it is licensed. For open source projects, say how it is licensed.
## Project status ## Project status
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers. If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.

2
Tests/.gitignore vendored
View File

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

View File

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

View File

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

View File

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

84
Web/.gitignore vendored
View File

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

View File

@@ -1,4 +1,4 @@
{ {
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846 // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
"recommendations": ["angular.ng-template"] "recommendations": ["angular.ng-template"]
} }

View File

@@ -1,21 +1,21 @@
{ {
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{ {
"name": "ng serve", "name": "ng serve",
"type": "chrome", "type": "chrome",
"request": "launch", "request": "launch",
"preLaunchTask": "npm: start", "preLaunchTask": "npm: start",
"url": "http://localhost:4200/", "url": "http://localhost:4200/",
"webRoot": "${workspaceFolder}/Web", "webRoot": "${workspaceFolder}/Web",
}, },
{ {
"name": "ng test", "name": "ng test",
"type": "chrome", "type": "chrome",
"request": "launch", "request": "launch",
"preLaunchTask": "npm: test", "preLaunchTask": "npm: test",
"url": "http://localhost:9876/debug.html" "url": "http://localhost:9876/debug.html"
} }
] ]
} }

View File

@@ -1,42 +1,42 @@
{ {
// For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558 // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
"version": "2.0.0", "version": "2.0.0",
"tasks": [ "tasks": [
{ {
"type": "npm", "type": "npm",
"script": "start", "script": "start",
"isBackground": true, "isBackground": true,
"problemMatcher": { "problemMatcher": {
"owner": "typescript", "owner": "typescript",
"pattern": "$tsc", "pattern": "$tsc",
"background": { "background": {
"activeOnStart": true, "activeOnStart": true,
"beginsPattern": { "beginsPattern": {
"regexp": "(.*?)" "regexp": "(.*?)"
}, },
"endsPattern": { "endsPattern": {
"regexp": "bundle generation complete" "regexp": "bundle generation complete"
} }
} }
} }
}, },
{ {
"type": "npm", "type": "npm",
"script": "test", "script": "test",
"isBackground": true, "isBackground": true,
"problemMatcher": { "problemMatcher": {
"owner": "typescript", "owner": "typescript",
"pattern": "$tsc", "pattern": "$tsc",
"background": { "background": {
"activeOnStart": true, "activeOnStart": true,
"beginsPattern": { "beginsPattern": {
"regexp": "(.*?)" "regexp": "(.*?)"
}, },
"endsPattern": { "endsPattern": {
"regexp": "bundle generation complete" "regexp": "bundle generation complete"
} }
} }
} }
} }
] ]
} }

View File

@@ -1,59 +1,59 @@
# Web # Web
This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 20.0.6. This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 20.0.6.
## Development server ## Development server
To start a local development server, run: To start a local development server, run:
```bash ```bash
ng serve ng serve
``` ```
Once the server is running, open your browser and navigate to `http://localhost:4200/`. The application will automatically reload whenever you modify any of the source files. Once the server is running, open your browser and navigate to `http://localhost:4200/`. The application will automatically reload whenever you modify any of the source files.
## Code scaffolding ## Code scaffolding
Angular CLI includes powerful code scaffolding tools. To generate a new component, run: Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
```bash ```bash
ng generate component component-name ng generate component component-name
``` ```
For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run: For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
```bash ```bash
ng generate --help ng generate --help
``` ```
## Building ## Building
To build the project run: To build the project run:
```bash ```bash
ng build ng build
``` ```
This will compile your project and store the build artifacts in the `dist/` directory. By default, the production build optimizes your application for performance and speed. This will compile your project and store the build artifacts in the `dist/` directory. By default, the production build optimizes your application for performance and speed.
## Running unit tests ## Running unit tests
To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command: To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
```bash ```bash
ng test ng test
``` ```
## Running end-to-end tests ## Running end-to-end tests
For end-to-end (e2e) testing, run: For end-to-end (e2e) testing, run:
```bash ```bash
ng e2e ng e2e
``` ```
Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs. Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
## Additional Resources ## Additional Resources
For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page. For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.

View File

@@ -1,100 +1,100 @@
{ {
"$schema": "./node_modules/@angular/cli/lib/config/schema.json", "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1, "version": 1,
"newProjectRoot": "projects", "newProjectRoot": "projects",
"projects": { "projects": {
"Web": { "Web": {
"projectType": "application", "projectType": "application",
"schematics": { "schematics": {
"@schematics/angular:component": { "@schematics/angular:component": {
"style": "scss" "style": "scss"
} }
}, },
"root": "", "root": "",
"sourceRoot": "src", "sourceRoot": "src",
"prefix": "app", "prefix": "app",
"architect": { "architect": {
"build": { "build": {
"builder": "@angular/build:application", "builder": "@angular/build:application",
"options": { "options": {
"browser": "src/main.ts", "browser": "src/main.ts",
"tsConfig": "tsconfig.app.json", "tsConfig": "tsconfig.app.json",
"inlineStyleLanguage": "scss", "inlineStyleLanguage": "scss",
"assets": [ "assets": [
{ {
"glob": "**/*", "glob": "**/*",
"input": "public" "input": "public"
} }
], ],
"styles": [ "styles": [
"src/styles.scss" "src/styles.scss"
] ]
}, },
"configurations": { "configurations": {
"production": { "production": {
"budgets": [ "budgets": [
{ {
"type": "initial", "type": "initial",
"maximumWarning": "500kB", "maximumWarning": "500kB",
"maximumError": "1MB" "maximumError": "1MB"
}, },
{ {
"type": "anyComponentStyle", "type": "anyComponentStyle",
"maximumWarning": "4kB", "maximumWarning": "4kB",
"maximumError": "8kB" "maximumError": "8kB"
} }
], ],
"outputHashing": "all" "outputHashing": "all"
}, },
"development": { "development": {
"optimization": false, "optimization": false,
"extractLicenses": false, "extractLicenses": false,
"sourceMap": true "sourceMap": true
} }
}, },
"defaultConfiguration": "production" "defaultConfiguration": "production"
}, },
"serve": { "serve": {
"builder": "@angular/build:dev-server", "builder": "@angular/build:dev-server",
"options": { "options": {
"allowedHosts": [ "allowedHosts": [
"localhost", "localhost",
"4200--0197f0a3-fef1-7776-b920-71d5d9c3d787.us01.gitpod.dev" "4200--0197f0a3-fef1-7776-b920-71d5d9c3d787.us01.gitpod.dev"
] ]
}, },
"configurations": { "configurations": {
"production": { "production": {
"buildTarget": "Web:build:production" "buildTarget": "Web:build:production"
}, },
"development": { "development": {
"buildTarget": "Web:build:development" "buildTarget": "Web:build:development"
} }
}, },
"defaultConfiguration": "development" "defaultConfiguration": "development"
}, },
"extract-i18n": { "extract-i18n": {
"builder": "@angular/build:extract-i18n" "builder": "@angular/build:extract-i18n"
}, },
"test": { "test": {
"builder": "@angular/build:karma", "builder": "@angular/build:karma",
"options": { "options": {
"tsConfig": "tsconfig.spec.json", "tsConfig": "tsconfig.spec.json",
"inlineStyleLanguage": "scss", "inlineStyleLanguage": "scss",
"assets": [ "assets": [
{ {
"glob": "**/*", "glob": "**/*",
"input": "public" "input": "public"
} }
], ],
"styles": [ "styles": [
"src/styles.scss" "src/styles.scss"
] ]
} }
} }
} }
} }
}, },
"cli": { "cli": {
"analytics": false "analytics": false
} }
} }

17828
Web/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,46 +1,46 @@
{ {
"name": "web", "name": "web",
"version": "0.0.0", "version": "0.0.0",
"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 --configuration=production", "build": "ng build --configuration=production",
"watch": "ng build --watch --configuration development", "watch": "ng build --watch --configuration development",
"test": "ng test" "test": "ng test"
}, },
"prettier": { "prettier": {
"overrides": [ "overrides": [
{ {
"files": "*.html", "files": "*.html",
"options": { "options": {
"parser": "angular" "parser": "angular"
} }
} }
] ]
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular/common": "^20.0.0", "@angular/common": "^20.0.0",
"@angular/compiler": "^20.0.0", "@angular/compiler": "^20.0.0",
"@angular/core": "^20.0.0", "@angular/core": "^20.0.0",
"@angular/forms": "^20.0.0", "@angular/forms": "^20.0.0",
"@angular/platform-browser": "^20.0.0", "@angular/platform-browser": "^20.0.0",
"@angular/router": "^20.0.0", "@angular/router": "^20.0.0",
"angular-oauth2-oidc": "^20.0.2", "angular-oauth2-oidc": "^20.0.2",
"rxjs": "~7.8.0", "rxjs": "~7.8.0",
"tslib": "^2.3.0" "tslib": "^2.3.0"
}, },
"devDependencies": { "devDependencies": {
"@angular/build": "^20.0.6", "@angular/build": "^20.0.6",
"@angular/cli": "^20.0.6", "@angular/cli": "^20.0.6",
"@angular/compiler-cli": "^20.0.0", "@angular/compiler-cli": "^20.0.0",
"@types/jasmine": "~5.1.0", "@types/jasmine": "~5.1.0",
"jasmine-core": "~5.7.0", "jasmine-core": "~5.7.0",
"karma": "~6.4.0", "karma": "~6.4.0",
"karma-chrome-launcher": "~3.2.0", "karma-chrome-launcher": "~3.2.0",
"karma-coverage": "~2.2.0", "karma-coverage": "~2.2.0",
"karma-jasmine": "~5.1.0", "karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.1.0", "karma-jasmine-html-reporter": "~2.1.0",
"typescript": "~5.8.2" "typescript": "~5.8.2"
} }
} }

View File

@@ -1,3 +1,3 @@
{ {
"apiEndpoint": "https://localhost:5001" "apiEndpoint": "https://localhost:5001"
} }

View File

@@ -1,34 +1,34 @@
import { ApplicationConfig, inject, provideAppInitializer, provideBrowserGlobalErrorListeners, provideZonelessChangeDetection } from '@angular/core'; import { ApplicationConfig, inject, provideAppInitializer, provideBrowserGlobalErrorListeners, provideZonelessChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router'; import { provideRouter } from '@angular/router';
import { routes } from './app.routes'; import { routes } from './app.routes';
import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
import { DefaultOAuthInterceptor, provideOAuthClient } from 'angular-oauth2-oidc'; import { DefaultOAuthInterceptor, provideOAuthClient } from 'angular-oauth2-oidc';
import { AppConfigService } from './services/config.service'; import { AppConfigService } from './services/config.service';
import { ApiEndpointInterceptor } from './services/http.interceptor'; import { ApiEndpointInterceptor } from './services/http.interceptor';
export const appConfig: ApplicationConfig = { export const appConfig: ApplicationConfig = {
providers: [ providers: [
provideBrowserGlobalErrorListeners(), provideBrowserGlobalErrorListeners(),
provideZonelessChangeDetection(), provideZonelessChangeDetection(),
provideRouter(routes), provideRouter(routes),
provideAppInitializer(() => inject(AppConfigService).loadConfig()), provideAppInitializer(() => inject(AppConfigService).loadConfig()),
{ {
provide: HTTP_INTERCEPTORS, provide: HTTP_INTERCEPTORS,
useClass: DefaultOAuthInterceptor, useClass: DefaultOAuthInterceptor,
multi: true, multi: true,
}, },
{ {
provide: HTTP_INTERCEPTORS, provide: HTTP_INTERCEPTORS,
useClass: ApiEndpointInterceptor, useClass: ApiEndpointInterceptor,
multi: true, multi: true,
}, },
provideHttpClient(withInterceptorsFromDi()), provideHttpClient(withInterceptorsFromDi()),
provideOAuthClient({ provideOAuthClient({
resourceServer: { resourceServer: {
allowedUrls: ['http://localhost:5000', 'https://localhost:5001', 'https://centrum.lesko.me','https://beta.e-dias.sk/'], allowedUrls: ['http://localhost:5000', 'https://localhost:5001', 'https://centrum.lesko.me','https://beta.e-dias.sk/'],
sendAccessToken: true, sendAccessToken: true,
}, },
}), }),
] ]
}; };

View File

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

View File

@@ -1,9 +1,9 @@
import { CanActivateFn } from '@angular/router'; import { CanActivateFn } from '@angular/router';
import { inject } from '@angular/core'; import { inject } from '@angular/core';
import { OAuthService } from 'angular-oauth2-oidc'; import { OAuthService } from 'angular-oauth2-oidc';
export const authGuard: CanActivateFn = (route, state) => { export const authGuard: CanActivateFn = (route, state) => {
const authService = inject(OAuthService); const authService = inject(OAuthService);
return authService.hasValidAccessToken(); // returns boolean, Promise, or Observable return authService.hasValidAccessToken(); // returns boolean, Promise, or Observable
}; };

View File

@@ -1,20 +1,20 @@
import { Routes } from '@angular/router'; import { Routes } from '@angular/router';
import { Login } from './login/login'; import { Login } from './login/login';
import { authGuard } from './app.route.guard'; import { authGuard } from './app.route.guard';
export const routes: Routes = [ export const routes: Routes = [
{ {
path: 'login', path: 'login',
component: Login, component: Login,
}, },
{ {
path: 'content', path: 'content',
children: [ children: [
{ {
path: '', path: '',
loadComponent: () => import('./content/content').then(m => m.Content), loadComponent: () => import('./content/content').then(m => m.Content),
canActivate: [authGuard], canActivate: [authGuard],
} }
], ],
} }
]; ];

View File

@@ -1,25 +1,25 @@
import { provideZonelessChangeDetection } from '@angular/core'; import { provideZonelessChangeDetection } from '@angular/core';
import { TestBed } from '@angular/core/testing'; import { TestBed } from '@angular/core/testing';
import { App } from './app'; import { App } from './app';
describe('App', () => { describe('App', () => {
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
imports: [App], imports: [App],
providers: [provideZonelessChangeDetection()] providers: [provideZonelessChangeDetection()]
}).compileComponents(); }).compileComponents();
}); });
it('should create the app', () => { it('should create the app', () => {
const fixture = TestBed.createComponent(App); const fixture = TestBed.createComponent(App);
const app = fixture.componentInstance; const app = fixture.componentInstance;
expect(app).toBeTruthy(); expect(app).toBeTruthy();
}); });
it('should render title', () => { it('should render title', () => {
const fixture = TestBed.createComponent(App); const fixture = TestBed.createComponent(App);
fixture.detectChanges(); fixture.detectChanges();
const compiled = fixture.nativeElement as HTMLElement; const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelector('h1')?.textContent).toContain('Hello, Web'); expect(compiled.querySelector('h1')?.textContent).toContain('Hello, Web');
}); });
}); });

View File

@@ -1,31 +1,31 @@
import { HTTP_INTERCEPTORS } from '@angular/common/http'; import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { APP_INITIALIZER, Component, inject, OnInit, provideAppInitializer } from '@angular/core'; import { APP_INITIALIZER, Component, inject, OnInit, provideAppInitializer } from '@angular/core';
import { Router, RouterOutlet } from '@angular/router'; import { Router, RouterOutlet } from '@angular/router';
import { DefaultOAuthInterceptor, OAuthService } from 'angular-oauth2-oidc'; import { DefaultOAuthInterceptor, OAuthService } from 'angular-oauth2-oidc';
import { AppConfigService } from './services/config.service'; import { AppConfigService } from './services/config.service';
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
imports: [RouterOutlet], imports: [RouterOutlet],
providers: [ providers: [
OAuthService, OAuthService,
], ],
templateUrl: './app.html', templateUrl: './app.html',
styleUrl: './app.scss' styleUrl: './app.scss'
}) })
export class App implements OnInit { export class App implements OnInit {
protected title = 'Web'; protected title = 'Web';
constructor(private readonly as: OAuthService, private readonly router: Router) { constructor(private readonly as: OAuthService, private readonly router: Router) {
this.as.configure({ this.as.configure({
issuer: 'https://identity.lesko.me', issuer: 'https://identity.lesko.me',
redirectUri: window.location.origin + '/login', redirectUri: window.location.origin + '/login',
clientId: '21131567-fea1-42a2-8907-21abd874eff8', clientId: '21131567-fea1-42a2-8907-21abd874eff8',
scope: 'openid profile email', scope: 'openid profile email',
responseType: 'code', responseType: 'code',
timeoutFactor: 0.01, timeoutFactor: 0.01,
}); });
} }
ngOnInit(): void { ngOnInit(): void {
this.as.loadDiscoveryDocumentAndLogin().then(() => this.router.navigate(['login'])); this.as.loadDiscoveryDocumentAndLogin().then(() => this.router.navigate(['login']));
} }
} }

View File

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

View File

@@ -1,22 +1,22 @@
import { JsonPipe } from '@angular/common'; import { JsonPipe } from '@angular/common';
import { HttpClient, HttpHeaders } from '@angular/common/http'; import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Component, isDevMode, signal } from '@angular/core'; import { Component, isDevMode, signal } from '@angular/core';
import { OAuthService } from 'angular-oauth2-oidc'; import { OAuthService } from 'angular-oauth2-oidc';
import { AppConfigService } from '../services/config.service'; import { AppConfigService } from '../services/config.service';
@Component({ @Component({
selector: 'app-content', selector: 'app-content',
imports: [JsonPipe], imports: [JsonPipe],
templateUrl: './content.html', templateUrl: './content.html',
styleUrl: './content.scss' styleUrl: './content.scss'
}) })
export class Content { export class Content {
data = signal({}); data = signal({});
constructor(httpClient: HttpClient, readonly as: OAuthService, readonly cs: AppConfigService) { constructor(httpClient: HttpClient, readonly as: OAuthService, readonly cs: AppConfigService) {
httpClient.get('/api/product') httpClient.get('/api/product')
.subscribe(data => { .subscribe(data => {
this.data.set(data); this.data.set(data);
}); });
} }
} }

View File

@@ -1,2 +1,2 @@
Logging in... Logging in...

View File

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

View File

@@ -1,33 +1,33 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { OAuthService } from 'angular-oauth2-oidc'; import { OAuthService } from 'angular-oauth2-oidc';
@Component({ @Component({
selector: 'app-login', selector: 'app-login',
templateUrl: './login.html', templateUrl: './login.html',
styleUrl: './login.scss' styleUrl: './login.scss'
}) })
export class Login implements OnInit { export class Login implements OnInit {
constructor(readonly as: OAuthService, readonly router: Router) { } constructor(readonly as: OAuthService, readonly router: Router) { }
ngOnInit(): void { ngOnInit(): void {
if (this.as.hasValidAccessToken() && this.as.hasValidIdToken()) { if (this.as.hasValidAccessToken() && this.as.hasValidIdToken()) {
this.getUserInfo(); this.getUserInfo();
} else { } else {
this.as.events.subscribe(event => { this.as.events.subscribe(event => {
if (event.type === 'token_received') if (event.type === 'token_received')
if (this.as.hasValidIdToken()) { if (this.as.hasValidIdToken()) {
this.getUserInfo(); this.getUserInfo();
} }
}) })
} }
} }
getUserInfo(): void { getUserInfo(): void {
this.as.loadUserProfile().then(value => { this.as.loadUserProfile().then(value => {
console.log('User profile loaded:', value); console.log('User profile loaded:', value);
this.router.navigate(['/content']); this.router.navigate(['/content']);
}); });
} }
} }

View File

@@ -1,31 +1,31 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
@Injectable({ providedIn: 'root' }) @Injectable({ providedIn: 'root' })
export class AppConfigService { export class AppConfigService {
private config: any; private config: any;
public loaded: boolean = false; public loaded: boolean = false;
constructor() { } constructor() { }
loadConfig(): Observable<any> { loadConfig(): Observable<any> {
return new Observable(observer => { return new Observable(observer => {
fetch('/config.json') fetch('/config.json')
.then(async response => { .then(async response => {
if (!response.ok) { if (!response.ok) {
throw new Error(`Could not load config.json: ${response.statusText}`); throw new Error(`Could not load config.json: ${response.statusText}`);
} }
this.config = await response.json(); this.config = await response.json();
this.loaded = true; this.loaded = true;
observer.next(this.config); observer.next(this.config);
observer.complete(); observer.complete();
}) })
.catch(error => observer.error(error)); .catch(error => observer.error(error));
}); });
} }
get setting() { get setting() {
return this.config; return this.config;
} }
} }

View File

@@ -1,25 +1,25 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http'; import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { AppConfigService } from './config.service'; import { AppConfigService } from './config.service';
@Injectable({ providedIn: 'root' }) @Injectable({ providedIn: 'root' })
export class ApiEndpointInterceptor implements HttpInterceptor { export class ApiEndpointInterceptor implements HttpInterceptor {
constructor(private readonly configService: AppConfigService) { } constructor(private readonly configService: AppConfigService) { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return this.prependUrl(req, next); return this.prependUrl(req, next);
} }
prependUrl(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { prependUrl(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const apiEndpoint = this.configService.setting.apiEndpoint; const apiEndpoint = this.configService.setting.apiEndpoint;
if (apiEndpoint === undefined || !this.configService.loaded) if (apiEndpoint === undefined || !this.configService.loaded)
throw new Error('API endpoint is not defined or config not loaded'); throw new Error('API endpoint is not defined or config not loaded');
const isRelative = !/^https?:\/\//i.test(req.url); const isRelative = !/^https?:\/\//i.test(req.url);
const url = isRelative ? `${apiEndpoint.replace(/\/$/, '')}/${req.url.replace(/^\//, '')}` : req.url; const url = isRelative ? `${apiEndpoint.replace(/\/$/, '')}/${req.url.replace(/^\//, '')}` : req.url;
const cloned = req.clone({ url }); const cloned = req.clone({ url });
console.trace('ApiEndpointInterceptor hit:', url); console.trace('ApiEndpointInterceptor hit:', url);
return next.handle(cloned); return next.handle(cloned);
} }
} }

View File

@@ -1,13 +1,13 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Web</title> <title>Web</title>
<base href="/"> <base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico"> <link rel="icon" type="image/x-icon" href="favicon.ico">
</head> </head>
<body> <body>
<app-root></app-root> <app-root></app-root>
</body> </body>
</html> </html>

View File

@@ -1,6 +1,6 @@
import { bootstrapApplication } from '@angular/platform-browser'; import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app/app.config'; import { appConfig } from './app/app.config';
import { App } from './app/app'; import { App } from './app/app';
bootstrapApplication(App, appConfig) bootstrapApplication(App, appConfig)
.catch((err) => console.error(err)); .catch((err) => console.error(err));

View File

@@ -1 +1 @@
/* You can add global styles to this file, and also import other style files */ /* You can add global styles to this file, and also import other style files */

View File

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

View File

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

View File

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

View File

@@ -1,96 +1,96 @@
{ {
"$schema": "./node_modules/@angular/cli/lib/config/schema.json", "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1, "version": 1,
"newProjectRoot": "projects", "newProjectRoot": "projects",
"projects": { "projects": {
"Modernize": { "Modernize": {
"projectType": "application", "projectType": "application",
"schematics": { "schematics": {
"@schematics/angular:component": { "@schematics/angular:component": {
"style": "scss" "style": "scss"
} }
}, },
"root": "", "root": "",
"sourceRoot": "src", "sourceRoot": "src",
"prefix": "app", "prefix": "app",
"architect": { "architect": {
"build": { "build": {
"builder": "@angular-devkit/build-angular:browser", "builder": "@angular-devkit/build-angular:browser",
"options": { "options": {
"allowedCommonJsDependencies": ["apexcharts", "bezier-easing", "moment"], "allowedCommonJsDependencies": ["apexcharts", "bezier-easing", "moment"],
"outputPath": "dist/Modernize", "outputPath": "dist/Modernize",
"index": "src/index.html", "index": "src/index.html",
"main": "src/main.ts", "main": "src/main.ts",
"polyfills": ["zone.js"], "polyfills": ["zone.js"],
"tsConfig": "tsconfig.app.json", "tsConfig": "tsconfig.app.json",
"inlineStyleLanguage": "scss", "inlineStyleLanguage": "scss",
"assets": ["src/favicon.ico", "src/assets"], "assets": ["src/favicon.ico", "src/assets"],
"styles": ["src/styles.scss", "src/assets/scss/style.scss"], "styles": ["src/styles.scss", "src/assets/scss/style.scss"],
"scripts": [] "scripts": []
}, },
"configurations": { "configurations": {
"production": { "production": {
"budgets": [ "budgets": [
{ {
"type": "initial", "type": "initial",
"maximumWarning": "12mb", "maximumWarning": "12mb",
"maximumError": "12mb" "maximumError": "12mb"
}, },
{ {
"type": "anyComponentStyle", "type": "anyComponentStyle",
"maximumWarning": "12mb", "maximumWarning": "12mb",
"maximumError": "12mb" "maximumError": "12mb"
} }
], ],
"outputHashing": "all" "outputHashing": "all"
}, },
"development": { "development": {
"buildOptimizer": false, "buildOptimizer": false,
"optimization": false, "optimization": false,
"vendorChunk": true, "vendorChunk": true,
"extractLicenses": false, "extractLicenses": false,
"sourceMap": true, "sourceMap": true,
"namedChunks": true "namedChunks": true
} }
}, },
"defaultConfiguration": "production" "defaultConfiguration": "production"
}, },
"serve": { "serve": {
"builder": "@angular-devkit/build-angular:dev-server", "builder": "@angular-devkit/build-angular:dev-server",
"configurations": { "configurations": {
"production": { "production": {
"buildTarget": "Modernize:build:production" "buildTarget": "Modernize:build:production"
}, },
"hmr": { "hmr": {
"hmr": true "hmr": true
}, },
"development": { "development": {
"buildTarget": "Modernize:build:development" "buildTarget": "Modernize:build:development"
} }
}, },
"defaultConfiguration": "development" "defaultConfiguration": "development"
}, },
"extract-i18n": { "extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n", "builder": "@angular-devkit/build-angular:extract-i18n",
"options": { "options": {
"buildTarget": "Modernize:build" "buildTarget": "Modernize:build"
} }
}, },
"test": { "test": {
"builder": "@angular-devkit/build-angular:karma", "builder": "@angular-devkit/build-angular:karma",
"options": { "options": {
"polyfills": ["zone.js", "zone.js/testing"], "polyfills": ["zone.js", "zone.js/testing"],
"tsConfig": "tsconfig.spec.json", "tsConfig": "tsconfig.spec.json",
"inlineStyleLanguage": "scss", "inlineStyleLanguage": "scss",
"assets": ["src/favicon.ico", "src/assets"], "assets": ["src/favicon.ico", "src/assets"],
"styles": ["src/styles.scss"], "styles": ["src/styles.scss"],
"scripts": [] "scripts": []
} }
} }
} }
} }
}, },
"cli": { "cli": {
"analytics": false "analytics": false
} }
} }

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,48 +1,48 @@
{ {
"name": "modernize", "name": "modernize",
"version": "0.0.0", "version": "0.0.0",
"scripts": { "scripts": {
"ng": "ng", "ng": "ng",
"start": "ng serve", "start": "ng serve",
"build": "ng build", "build": "ng build",
"watch": "ng build --watch --configuration development", "watch": "ng build --watch --configuration development",
"test": "ng test" "test": "ng test"
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular/animations": "^19.0.0", "@angular/animations": "^19.0.0",
"@angular/cdk": "^19.0.0", "@angular/cdk": "^19.0.0",
"@angular/common": "^19.0.0", "@angular/common": "^19.0.0",
"@angular/compiler": "^19.0.0", "@angular/compiler": "^19.0.0",
"@angular/core": "^19.0.0", "@angular/core": "^19.0.0",
"@angular/forms": "^19.0.0", "@angular/forms": "^19.0.0",
"@angular/material": "^19.0.0", "@angular/material": "^19.0.0",
"@angular/platform-browser": "^19.0.0", "@angular/platform-browser": "^19.0.0",
"@angular/platform-browser-dynamic": "^19.0.0", "@angular/platform-browser-dynamic": "^19.0.0",
"@angular/router": "^19.0.0", "@angular/router": "^19.0.0",
"@ngx-translate/core": "^14.0.0", "@ngx-translate/core": "^14.0.0",
"@ngx-translate/http-loader": "^7.0.0", "@ngx-translate/http-loader": "^7.0.0",
"angular-tabler-icons": "^2.7.0", "angular-tabler-icons": "^2.7.0",
"apexcharts": "^3.49.0", "apexcharts": "^3.49.0",
"ng-apexcharts": "1.7.6", "ng-apexcharts": "1.7.6",
"ngx-scrollbar": "^11.0.0", "ngx-scrollbar": "^11.0.0",
"rxjs": "~7.5.0", "rxjs": "~7.5.0",
"sass": "1.81.0", "sass": "1.81.0",
"tslib": "^2.3.0", "tslib": "^2.3.0",
"zone.js": "~0.15.0" "zone.js": "~0.15.0"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "^19.0.1", "@angular-devkit/build-angular": "^19.0.1",
"@angular/cli": "~19.0.1", "@angular/cli": "~19.0.1",
"@angular/compiler-cli": "^19.0.0", "@angular/compiler-cli": "^19.0.0",
"@types/date-fns": "^2.6.0", "@types/date-fns": "^2.6.0",
"@types/jasmine": "~4.3.0", "@types/jasmine": "~4.3.0",
"jasmine-core": "~4.5.0", "jasmine-core": "~4.5.0",
"karma": "~6.4.0", "karma": "~6.4.0",
"karma-chrome-launcher": "~3.1.0", "karma-chrome-launcher": "~3.1.0",
"karma-coverage": "~2.2.0", "karma-coverage": "~2.2.0",
"karma-jasmine": "~5.1.0", "karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.0.0", "karma-jasmine-html-reporter": "~2.0.0",
"typescript": "~5.6.3" "typescript": "~5.6.3"
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,51 +1,51 @@
import { Routes } from '@angular/router'; import { Routes } from '@angular/router';
import { BlankComponent } from './layouts/blank/blank.component'; import { BlankComponent } from './layouts/blank/blank.component';
import { FullComponent } from './layouts/full/full.component'; import { FullComponent } from './layouts/full/full.component';
export const routes: Routes = [ export const routes: Routes = [
{ {
path: '', path: '',
component: FullComponent, component: FullComponent,
children: [ children: [
{ {
path: '', path: '',
redirectTo: '/dashboard', redirectTo: '/dashboard',
pathMatch: 'full', pathMatch: 'full',
}, },
{ {
path: 'dashboard', path: 'dashboard',
loadChildren: () => loadChildren: () =>
import('./pages/pages.routes').then((m) => m.PagesRoutes), import('./pages/pages.routes').then((m) => m.PagesRoutes),
}, },
{ {
path: 'ui-components', path: 'ui-components',
loadChildren: () => loadChildren: () =>
import('./pages/ui-components/ui-components.routes').then( import('./pages/ui-components/ui-components.routes').then(
(m) => m.UiComponentsRoutes (m) => m.UiComponentsRoutes
), ),
}, },
{ {
path: 'extra', path: 'extra',
loadChildren: () => loadChildren: () =>
import('./pages/extra/extra.routes').then((m) => m.ExtraRoutes), import('./pages/extra/extra.routes').then((m) => m.ExtraRoutes),
}, },
], ],
}, },
{ {
path: '', path: '',
component: BlankComponent, component: BlankComponent,
children: [ children: [
{ {
path: 'authentication', path: 'authentication',
loadChildren: () => loadChildren: () =>
import('./pages/authentication/authentication.routes').then( import('./pages/authentication/authentication.routes').then(
(m) => m.AuthenticationRoutes (m) => m.AuthenticationRoutes
), ),
}, },
], ],
}, },
{ {
path: '**', path: '**',
redirectTo: 'authentication/error', redirectTo: 'authentication/error',
}, },
]; ];

View File

@@ -1,32 +1,32 @@
<div class="row"> <div class="row">
@for(productcard of productcards; track productcards) { @for(productcard of productcards; track productcards) {
<div class="col-sm-6 col-lg-3"> <div class="col-sm-6 col-lg-3">
<mat-card class="cardWithShadow productcard overflow-hidden"> <mat-card class="cardWithShadow productcard overflow-hidden">
<a routerLink="/widgets/cards"> <a routerLink="/widgets/cards">
<img src="{{ productcard.imgSrc }}" alt="imgSrc" class="w-100" mat-card-image /> <img src="{{ productcard.imgSrc }}" alt="imgSrc" class="w-100" mat-card-image />
</a> </a>
<mat-card-content class="p-b-24 p-t-12 position-relative"> <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"> <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> <i-tabler name="basket" class="icon-16"></i-tabler>
</button> </button>
<mat-card-title class="mat-headline-2 f-s-16 m-b-4">{{ <mat-card-title class="mat-headline-2 f-s-16 m-b-4">{{
productcard.title productcard.title
}}</mat-card-title> }}</mat-card-title>
<div class="d-flex align-items-center justify-content-between"> <div class="d-flex align-items-center justify-content-between">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<h6 class="f-w-600 f-s-16">${{ productcard.price }}</h6> <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> <span class="f-s-14 m-l-4 text-decoration-line-through">${{ productcard.rprice }}</span>
</div> </div>
<div class="m-l-auto d-flex gap-4"> <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> <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>
</div> </div>
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>
</div> </div>
} }
</div> </div>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,33 +1,33 @@
<mat-card class="cardWithShadow"> <mat-card class="cardWithShadow">
<mat-card-content> <mat-card-content>
<mat-card-title>Recent Transactions</mat-card-title> <mat-card-title>Recent Transactions</mat-card-title>
<div class="timeline m-t-24"> <div class="timeline m-t-24">
@for(stat of stats; track stat.title) { @for(stat of stats; track stat.title) {
<div class="timeline-item d-flex overflow-hidden"> <div class="timeline-item d-flex overflow-hidden">
<div class="time text-right f-s-14">{{ stat.time }}</div> <div class="time text-right f-s-14">{{ stat.time }}</div>
<div class="point d-flex align-items-center"> <div class="point d-flex align-items-center">
<span class="timeline-badge border-{{ stat.color }} m-y-8"></span> <span class="timeline-badge border-{{ stat.color }} m-y-8"></span>
<span class="timline-border d-block"></span> <span class="timline-border d-block"></span>
</div> </div>
<div class="desc"> <div class="desc">
@if(stat.subtext) { @if(stat.subtext) {
<span class="f-s-14 lh-20">{{ stat.subtext }}</span> <span class="f-s-14 lh-20">{{ stat.subtext }}</span>
} }
@if(stat.title) { @if(stat.title) {
<span class="f-s-14 lh-20 f-w-600 d-block">{{ <span class="f-s-14 lh-20 f-w-600 d-block">{{
stat.title stat.title
}}</span> }}</span>
} }
@if(stat.link) { @if(stat.link) {
<a href="#" class="text-primary text-decoration-none f-s-14">#ML-3467</a> <a href="#" class="text-primary text-decoration-none f-s-14">#ML-3467</a>
} }
</div> </div>
</div> </div>
} }
</div> </div>
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>

View File

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

View File

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

View File

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

View File

@@ -1,34 +1,34 @@
<mat-card class="cardWithShadow"> <mat-card class="cardWithShadow">
<mat-card-content> <mat-card-content>
<mat-card-title>Yearly Breakup</mat-card-title> <mat-card-title>Yearly Breakup</mat-card-title>
<div class="row m-t-24"> <div class="row m-t-24">
<div class="col-7"> <div class="col-7">
<h4 class="f-s-24">$36,358</h4> <h4 class="f-s-24">$36,358</h4>
<div class="d-flex align-items-center m-t-16"> <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"> <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> <i-tabler name="arrow-up-right" class="icon-20 d-flex align-items-center"></i-tabler>
</button> </button>
<div class="f-w-600 m-l-12 f-s-14">+9%</div> <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 class="m-l-4 f-s-14">last year</div>
</div> </div>
<div class="d-flex align-items-center m-t-32"> <div class="d-flex align-items-center m-t-32">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<i-tabler name="circle-filled" class="text-primary icon-12 d-flex"></i-tabler> <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 class="m-l-12 f-s-14">2025</div>
</div> </div>
<div class="d-flex align-items-center m-l-16"> <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> <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 class="m-l-12 f-s-14">2024</div>
</div> </div>
</div> </div>
</div> </div>
<div class="col-5 d-flex align-items-start"> <div class="col-5 d-flex align-items-start">
<apx-chart [series]="yearlyChart.series" [dataLabels]="yearlyChart.dataLabels" <apx-chart [series]="yearlyChart.series" [dataLabels]="yearlyChart.dataLabels"
[chart]="yearlyChart.chart" [legend]="yearlyChart.legend" [colors]="yearlyChart.colors" [chart]="yearlyChart.chart" [legend]="yearlyChart.legend" [colors]="yearlyChart.colors"
[stroke]="yearlyChart.stroke" [tooltip]="yearlyChart.tooltip" [stroke]="yearlyChart.stroke" [tooltip]="yearlyChart.tooltip"
[plotOptions]="yearlyChart.plotOptions" [responsive]="yearlyChart.responsive"></apx-chart> [plotOptions]="yearlyChart.plotOptions" [responsive]="yearlyChart.responsive"></apx-chart>
</div> </div>
</div> </div>
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>

View File

@@ -1,101 +1,101 @@
import { Component, ViewEncapsulation, ViewChild } from '@angular/core'; import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
import { TablerIconsModule } from 'angular-tabler-icons'; import { TablerIconsModule } from 'angular-tabler-icons';
import { import {
ApexChart, ApexChart,
ChartComponent, ChartComponent,
ApexDataLabels, ApexDataLabels,
ApexLegend, ApexLegend,
ApexStroke, ApexStroke,
ApexTooltip, ApexTooltip,
ApexAxisChartSeries, ApexAxisChartSeries,
ApexXAxis, ApexXAxis,
ApexYAxis, ApexYAxis,
ApexGrid, ApexGrid,
ApexPlotOptions, ApexPlotOptions,
ApexFill, ApexFill,
ApexMarkers, ApexMarkers,
ApexResponsive, ApexResponsive,
NgApexchartsModule, NgApexchartsModule,
} from 'ng-apexcharts'; } from 'ng-apexcharts';
import { MaterialModule } from 'src/app/material.module'; import { MaterialModule } from 'src/app/material.module';
export interface yearlyChart { export interface yearlyChart {
series: ApexAxisChartSeries; series: ApexAxisChartSeries;
chart: ApexChart; chart: ApexChart;
dataLabels: ApexDataLabels; dataLabels: ApexDataLabels;
plotOptions: ApexPlotOptions; plotOptions: ApexPlotOptions;
tooltip: ApexTooltip; tooltip: ApexTooltip;
stroke: ApexStroke; stroke: ApexStroke;
legend: ApexLegend; legend: ApexLegend;
responsive: ApexResponsive; responsive: ApexResponsive;
} }
@Component({ @Component({
selector: 'app-yearly-breakup', selector: 'app-yearly-breakup',
templateUrl: './yearly-breakup.component.html', templateUrl: './yearly-breakup.component.html',
imports: [MaterialModule, NgApexchartsModule, TablerIconsModule], imports: [MaterialModule, NgApexchartsModule, TablerIconsModule],
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None,
}) })
export class AppYearlyBreakupComponent { export class AppYearlyBreakupComponent {
@ViewChild('chart') chart: ChartComponent = Object.create(null); @ViewChild('chart') chart: ChartComponent = Object.create(null);
public yearlyChart!: Partial<yearlyChart> | any; public yearlyChart!: Partial<yearlyChart> | any;
constructor() { constructor() {
this.yearlyChart = { this.yearlyChart = {
color: "#adb5bd", color: "#adb5bd",
series: [38, 40, 25], series: [38, 40, 25],
labels: ["2025", "2024", "2023"], labels: ["2025", "2024", "2023"],
chart: { chart: {
width: 125, width: 125,
type: "donut", type: "donut",
fontFamily: "inherit", fontFamily: "inherit",
foreColor: "#adb0bb", foreColor: "#adb0bb",
}, },
plotOptions: { plotOptions: {
pie: { pie: {
startAngle: 0, startAngle: 0,
endAngle: 360, endAngle: 360,
donut: { donut: {
size: "75%", size: "75%",
}, },
}, },
}, },
stroke: { stroke: {
show: false, show: false,
}, },
dataLabels: { dataLabels: {
enabled: false, enabled: false,
}, },
legend: { legend: {
show: false, show: false,
}, },
colors: ['#5D87FF', '#ECF2FF', '#F9F9FD'], colors: ['#5D87FF', '#ECF2FF', '#F9F9FD'],
responsive: [ responsive: [
{ {
breakpoint: 991, breakpoint: 991,
options: { options: {
chart: { chart: {
width: 120, width: 120,
}, },
}, },
}, },
], ],
tooltip: { tooltip: {
theme: "dark", theme: "dark",
fillSeriesColor: false, fillSeriesColor: false,
}, },
}; };
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,117 +1,117 @@
import { BreakpointObserver, MediaMatcher } from '@angular/cdk/layout'; import { BreakpointObserver, MediaMatcher } from '@angular/cdk/layout';
import { Component, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; import { Component, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { MatSidenav, MatSidenavContent } from '@angular/material/sidenav'; import { MatSidenav, MatSidenavContent } from '@angular/material/sidenav';
import { CoreService } from 'src/app/services/core.service'; import { CoreService } from 'src/app/services/core.service';
import { filter } from 'rxjs/operators'; import { filter } from 'rxjs/operators';
import { NavigationEnd, Router } from '@angular/router'; import { NavigationEnd, Router } from '@angular/router';
import { NavService } from '../../services/nav.service'; import { NavService } from '../../services/nav.service';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { MaterialModule } from 'src/app/material.module'; import { MaterialModule } from 'src/app/material.module';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { NgScrollbarModule } from 'ngx-scrollbar'; import { NgScrollbarModule } from 'ngx-scrollbar';
import { TablerIconsModule } from 'angular-tabler-icons'; import { TablerIconsModule } from 'angular-tabler-icons';
import { HeaderComponent } from './header/header.component'; import { HeaderComponent } from './header/header.component';
import { SidebarComponent } from './sidebar/sidebar.component'; import { SidebarComponent } from './sidebar/sidebar.component';
import { AppNavItemComponent } from './sidebar/nav-item/nav-item.component'; import { AppNavItemComponent } from './sidebar/nav-item/nav-item.component';
import { navItems } from './sidebar/sidebar-data'; import { navItems } from './sidebar/sidebar-data';
import { AppTopstripComponent } from './top-strip/topstrip.component'; import { AppTopstripComponent } from './top-strip/topstrip.component';
const MOBILE_VIEW = 'screen and (max-width: 768px)'; const MOBILE_VIEW = 'screen and (max-width: 768px)';
const TABLET_VIEW = 'screen and (min-width: 769px) and (max-width: 1024px)'; const TABLET_VIEW = 'screen and (min-width: 769px) and (max-width: 1024px)';
@Component({ @Component({
selector: 'app-full', selector: 'app-full',
imports: [ imports: [
RouterModule, RouterModule,
AppNavItemComponent, AppNavItemComponent,
MaterialModule, MaterialModule,
CommonModule, CommonModule,
SidebarComponent, SidebarComponent,
NgScrollbarModule, NgScrollbarModule,
TablerIconsModule, TablerIconsModule,
HeaderComponent, HeaderComponent,
AppTopstripComponent AppTopstripComponent
], ],
templateUrl: './full.component.html', templateUrl: './full.component.html',
styleUrls: [], styleUrls: [],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class FullComponent implements OnInit { export class FullComponent implements OnInit {
navItems = navItems; navItems = navItems;
@ViewChild('leftsidenav') @ViewChild('leftsidenav')
public sidenav: MatSidenav; public sidenav: MatSidenav;
resView = false; resView = false;
@ViewChild('content', { static: true }) content!: MatSidenavContent; @ViewChild('content', { static: true }) content!: MatSidenavContent;
//get options from service //get options from service
options = this.settings.getOptions(); options = this.settings.getOptions();
private layoutChangesSubscription = Subscription.EMPTY; private layoutChangesSubscription = Subscription.EMPTY;
private isMobileScreen = false; private isMobileScreen = false;
private isContentWidthFixed = true; private isContentWidthFixed = true;
private isCollapsedWidthFixed = false; private isCollapsedWidthFixed = false;
private htmlElement!: HTMLHtmlElement; private htmlElement!: HTMLHtmlElement;
get isOver(): boolean { get isOver(): boolean {
return this.isMobileScreen; return this.isMobileScreen;
} }
constructor( constructor(
private settings: CoreService, private settings: CoreService,
private router: Router, private router: Router,
private breakpointObserver: BreakpointObserver, private breakpointObserver: BreakpointObserver,
) { ) {
this.htmlElement = document.querySelector('html')!; this.htmlElement = document.querySelector('html')!;
this.layoutChangesSubscription = this.breakpointObserver this.layoutChangesSubscription = this.breakpointObserver
.observe([MOBILE_VIEW, TABLET_VIEW]) .observe([MOBILE_VIEW, TABLET_VIEW])
.subscribe((state) => { .subscribe((state) => {
// SidenavOpened must be reset true when layout changes // SidenavOpened must be reset true when layout changes
this.options.sidenavOpened = true; this.options.sidenavOpened = true;
this.isMobileScreen = state.breakpoints[MOBILE_VIEW]; this.isMobileScreen = state.breakpoints[MOBILE_VIEW];
if (this.options.sidenavCollapsed == false) { if (this.options.sidenavCollapsed == false) {
this.options.sidenavCollapsed = state.breakpoints[TABLET_VIEW]; this.options.sidenavCollapsed = state.breakpoints[TABLET_VIEW];
} }
}); });
// Initialize project theme with options // Initialize project theme with options
// This is for scroll to top // This is for scroll to top
this.router.events this.router.events
.pipe(filter((event) => event instanceof NavigationEnd)) .pipe(filter((event) => event instanceof NavigationEnd))
.subscribe((e) => { .subscribe((e) => {
this.content.scrollTo({ top: 0 }); this.content.scrollTo({ top: 0 });
}); });
} }
ngOnInit(): void { } ngOnInit(): void { }
ngOnDestroy() { ngOnDestroy() {
this.layoutChangesSubscription.unsubscribe(); this.layoutChangesSubscription.unsubscribe();
} }
toggleCollapsed() { toggleCollapsed() {
this.isContentWidthFixed = false; this.isContentWidthFixed = false;
this.options.sidenavCollapsed = !this.options.sidenavCollapsed; this.options.sidenavCollapsed = !this.options.sidenavCollapsed;
this.resetCollapsedState(); this.resetCollapsedState();
} }
resetCollapsedState(timer = 400) { resetCollapsedState(timer = 400) {
setTimeout(() => this.settings.setOptions(this.options), timer); setTimeout(() => this.settings.setOptions(this.options), timer);
} }
onSidenavClosedStart() { onSidenavClosedStart() {
this.isContentWidthFixed = false; this.isContentWidthFixed = false;
} }
onSidenavOpenedChange(isOpened: boolean) { onSidenavOpenedChange(isOpened: boolean) {
this.isCollapsedWidthFixed = !this.isOver; this.isCollapsedWidthFixed = !this.isOver;
this.options.sidenavOpened = isOpened; this.options.sidenavOpened = isOpened;
//this.settings.setOptions(this.options); //this.settings.setOptions(this.options);
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,77 +1,77 @@
import { import {
Component, Component,
HostBinding, HostBinding,
Input, Input,
OnChanges, OnChanges,
Output, Output,
EventEmitter, EventEmitter,
} from '@angular/core'; } from '@angular/core';
import { NavItem } from './nav-item'; import { NavItem } from './nav-item';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { NavService } from '../../../../services/nav.service'; import { NavService } from '../../../../services/nav.service';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { TablerIconsModule } from 'angular-tabler-icons'; import { TablerIconsModule } from 'angular-tabler-icons';
import { MaterialModule } from 'src/app/material.module'; import { MaterialModule } from 'src/app/material.module';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
@Component({ @Component({
selector: 'app-nav-item', selector: 'app-nav-item',
imports: [TranslateModule, TablerIconsModule, MaterialModule, CommonModule], imports: [TranslateModule, TablerIconsModule, MaterialModule, CommonModule],
templateUrl: './nav-item.component.html', templateUrl: './nav-item.component.html',
styleUrls: [], styleUrls: [],
}) })
export class AppNavItemComponent implements OnChanges { export class AppNavItemComponent implements OnChanges {
@Output() notify: EventEmitter<boolean> = new EventEmitter<boolean>(); @Output() notify: EventEmitter<boolean> = new EventEmitter<boolean>();
@Input() item: NavItem | any; @Input() item: NavItem | any;
expanded: any = false; expanded: any = false;
@HostBinding('attr.aria-expanded') ariaExpanded = this.expanded; @HostBinding('attr.aria-expanded') ariaExpanded = this.expanded;
@Input() depth: any; @Input() depth: any;
constructor(public navService: NavService, public router: Router) {} constructor(public navService: NavService, public router: Router) {}
ngOnChanges() { ngOnChanges() {
const url = this.navService.currentUrl(); const url = this.navService.currentUrl();
if (this.item.route && url) { if (this.item.route && url) {
this.expanded = url.indexOf(`/${this.item.route}`) === 0; this.expanded = url.indexOf(`/${this.item.route}`) === 0;
this.ariaExpanded = this.expanded; this.ariaExpanded = this.expanded;
} }
} }
onItemSelected(item: NavItem) { onItemSelected(item: NavItem) {
if (!item.children || !item.children.length) { if (!item.children || !item.children.length) {
this.router.navigate([item.route]); this.router.navigate([item.route]);
} }
if (item.children && item.children.length) { if (item.children && item.children.length) {
this.expanded = !this.expanded; this.expanded = !this.expanded;
} }
//scroll //scroll
window.scroll({ window.scroll({
top: 0, top: 0,
left: 0, left: 0,
behavior: 'smooth', behavior: 'smooth',
}); });
if (!this.expanded) { if (!this.expanded) {
if (window.innerWidth < 1024) { if (window.innerWidth < 1024) {
this.notify.emit(); this.notify.emit();
} }
} }
} }
openExternalLink(url: string): void { openExternalLink(url: string): void {
if (url) { if (url) {
window.open(url, '_blank'); window.open(url, '_blank');
} }
} }
onSubItemSelected(item: NavItem) { onSubItemSelected(item: NavItem) {
if (!item.children || !item.children.length) { if (!item.children || !item.children.length) {
if (this.expanded && window.innerWidth < 1024) { if (this.expanded && window.innerWidth < 1024) {
this.notify.emit(); this.notify.emit();
} }
} }
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,20 +1,20 @@
import { Routes } from '@angular/router'; import { Routes } from '@angular/router';
import { AppSideLoginComponent } from './side-login/side-login.component'; import { AppSideLoginComponent } from './side-login/side-login.component';
import { AppSideRegisterComponent } from './side-register/side-register.component'; import { AppSideRegisterComponent } from './side-register/side-register.component';
export const AuthenticationRoutes: Routes = [ export const AuthenticationRoutes: Routes = [
{ {
path: '', path: '',
children: [ children: [
{ {
path: 'login', path: 'login',
component: AppSideLoginComponent, component: AppSideLoginComponent,
}, },
{ {
path: 'register', path: 'register',
component: AppSideRegisterComponent, component: AppSideRegisterComponent,
}, },
], ],
}, },
]; ];

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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