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:
@@ -1,20 +1,19 @@
|
||||
FROM mcr.microsoft.com/devcontainers/dotnet:1-8.0-bookworm
|
||||
|
||||
# Install SQL Tools: SQLPackage and sqlcmd
|
||||
COPY mssql/installSQLtools.sh installSQLtools.sh
|
||||
RUN bash ./installSQLtools.sh \
|
||||
&& 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 - && \
|
||||
# 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
|
||||
# [Optional] Uncomment this section to install additional OS packages.
|
||||
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
||||
# && apt-get -y install --no-install-recommends <your-package-list-here>
|
||||
|
||||
ENV ASPNETCORE_HTTP_PORTS=5000
|
||||
|
||||
EXPOSE 4200
|
||||
# [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 && npm install -g <your-package-here>" 2>&1
|
||||
FROM mcr.microsoft.com/devcontainers/dotnet:1-8.0-bookworm
|
||||
|
||||
# Install SQL Tools: SQLPackage and sqlcmd
|
||||
COPY mssql/installSQLtools.sh installSQLtools.sh
|
||||
RUN bash ./installSQLtools.sh && 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 - && \
|
||||
# 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
|
||||
# [Optional] Uncomment this section to install additional OS packages.
|
||||
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
||||
# && apt-get -y install --no-install-recommends <your-package-list-here>
|
||||
|
||||
ENV ASPNETCORE_HTTP_PORTS=5000
|
||||
|
||||
EXPOSE 4200
|
||||
# [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 && npm install -g <your-package-here>" 2>&1
|
||||
|
||||
@@ -1,59 +1,59 @@
|
||||
// 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
|
||||
{
|
||||
"name": ".NET (C#), Node.js (TypeScript) & MS SQL",
|
||||
"dockerComposeFile": "docker-compose.yml",
|
||||
"service": "app",
|
||||
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
|
||||
// Features to add to the dev container. More info: https://containers.dev/features.
|
||||
// "features": {},
|
||||
// Configure tool-specific properties.
|
||||
"customizations": {
|
||||
// Configure properties specific to VS Code.
|
||||
"vscode": {
|
||||
// Set *default* container specific settings.json values on container create.
|
||||
"settings": {
|
||||
"mssql.connections": [
|
||||
{
|
||||
"server": "localhost,1433",
|
||||
"database": "",
|
||||
"authenticationType": "SqlLogin",
|
||||
"user": "sa",
|
||||
"password": "P@ssw0rd",
|
||||
"emptyPasswordInput": false,
|
||||
"savePassword": false,
|
||||
"profileName": "mssql-container"
|
||||
}
|
||||
]
|
||||
},
|
||||
// Add the IDs of extensions you want installed when the container is created.
|
||||
"extensions": [
|
||||
"ms-dotnettools.csharp",
|
||||
"ms-mssql.mssql"
|
||||
]
|
||||
}
|
||||
},
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
"forwardPorts": [
|
||||
4200,
|
||||
5000,
|
||||
5001,
|
||||
1433
|
||||
],
|
||||
"portsAttributes": {
|
||||
"5001": {
|
||||
"protocol": "https"
|
||||
},
|
||||
"1433": {
|
||||
"protocol": "tcp"
|
||||
}
|
||||
},
|
||||
// postCreateCommand.sh parameters: $1=SA password, $2=dacpac path, $3=sql script(s) path
|
||||
"containerEnv": {
|
||||
"SA_PASSWORD": "P@ssw0rd",
|
||||
"ACCEPT_EULA": "Y"
|
||||
},
|
||||
"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.
|
||||
// "remoteUser": "root"
|
||||
// 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
|
||||
{
|
||||
"name": ".NET (C#), Node.js (TypeScript) & MS SQL",
|
||||
"dockerComposeFile": "docker-compose.yml",
|
||||
"service": "app",
|
||||
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
|
||||
// Features to add to the dev container. More info: https://containers.dev/features.
|
||||
// "features": {},
|
||||
// Configure tool-specific properties.
|
||||
"customizations": {
|
||||
// Configure properties specific to VS Code.
|
||||
"vscode": {
|
||||
// Set *default* container specific settings.json values on container create.
|
||||
"settings": {
|
||||
"mssql.connections": [
|
||||
{
|
||||
"server": "localhost,1433",
|
||||
"database": "",
|
||||
"authenticationType": "SqlLogin",
|
||||
"user": "sa",
|
||||
"password": "P@ssw0rd",
|
||||
"emptyPasswordInput": false,
|
||||
"savePassword": false,
|
||||
"profileName": "mssql-container"
|
||||
}
|
||||
]
|
||||
},
|
||||
// Add the IDs of extensions you want installed when the container is created.
|
||||
"extensions": [
|
||||
"ms-dotnettools.csharp",
|
||||
"ms-mssql.mssql"
|
||||
]
|
||||
}
|
||||
},
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
"forwardPorts": [
|
||||
4200,
|
||||
5000,
|
||||
5001,
|
||||
1433
|
||||
],
|
||||
"portsAttributes": {
|
||||
"5001": {
|
||||
"protocol": "https"
|
||||
},
|
||||
"1433": {
|
||||
"protocol": "tcp"
|
||||
}
|
||||
},
|
||||
// postCreateCommand.sh parameters: $1=SA password, $2=dacpac path, $3=sql script(s) path
|
||||
"containerEnv": {
|
||||
"SA_PASSWORD": "P@ssw0rd",
|
||||
"ACCEPT_EULA": "Y"
|
||||
},
|
||||
"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.
|
||||
// "remoteUser": "root"
|
||||
}
|
||||
@@ -1,34 +1,34 @@
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
|
||||
volumes:
|
||||
- ../..:/workspaces:cached
|
||||
|
||||
# Overrides default command so things don't shut down after the process ends.
|
||||
command: sleep infinity
|
||||
ports:
|
||||
- "4200:4200"
|
||||
# Runs app on the same network as the database container, allows "forwardPorts" in devcontainer.json function.
|
||||
network_mode: host
|
||||
|
||||
# Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||
# user: root
|
||||
|
||||
# Use "forwardPorts" in **devcontainer.json** to forward an app port locally.
|
||||
# (Adding the "ports" property to this file will not forward from a Codespace.)
|
||||
|
||||
db:
|
||||
image: mcr.microsoft.com/mssql/server:2019-latest
|
||||
restart: unless-stopped
|
||||
network_mode: host
|
||||
environment:
|
||||
SA_PASSWORD: P@ssw0rd
|
||||
ACCEPT_EULA: Y
|
||||
|
||||
# Add "forwardPorts": ["db:1433"] to **devcontainer.json** to forward MSSQL locally.
|
||||
# (Adding the "ports" property to this file will not forward from a Codespace.)
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
|
||||
volumes:
|
||||
- ../..:/workspaces:cached
|
||||
|
||||
# Overrides default command so things don't shut down after the process ends.
|
||||
command: sleep infinity
|
||||
ports:
|
||||
- "4200:4200"
|
||||
# Runs app on the same network as the database container, allows "forwardPorts" in devcontainer.json function.
|
||||
network_mode: host
|
||||
|
||||
# Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||
# user: root
|
||||
|
||||
# Use "forwardPorts" in **devcontainer.json** to forward an app port locally.
|
||||
# (Adding the "ports" property to this file will not forward from a Codespace.)
|
||||
|
||||
db:
|
||||
image: mcr.microsoft.com/mssql/server:2019-latest
|
||||
restart: unless-stopped
|
||||
network_mode: host
|
||||
environment:
|
||||
SA_PASSWORD: P@ssw0rd
|
||||
ACCEPT_EULA: Y
|
||||
|
||||
# Add "forwardPorts": ["db:1433"] to **devcontainer.json** to forward MSSQL locally.
|
||||
# (Adding the "ports" property to this file will not forward from a Codespace.)
|
||||
|
||||
64
.devcontainer/mssql/postCreateCommand-backup.sh
Normal file
64
.devcontainer/mssql/postCreateCommand-backup.sh
Normal 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
|
||||
@@ -5,60 +5,9 @@ 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
|
||||
cd Api
|
||||
dotnet restore ./Api.csproj
|
||||
dotnet build ./Api.csproj
|
||||
dotnet tool install --global dotnet-ef --version 8.*
|
||||
export PATH="$PATH:/root/.dotnet/tools"
|
||||
dotnet-ef database update --project ./Api.csproj --startup-project ./Api.csproj
|
||||
@@ -1,2 +0,0 @@
|
||||
CREATE DATABASE ApplicationDB;
|
||||
GO
|
||||
24
.github/dependabot.yml
vendored
24
.github/dependabot.yml
vendored
@@ -1,12 +1,12 @@
|
||||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for more information:
|
||||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
# https://containers.dev/guide/dependabot
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "devcontainers"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: weekly
|
||||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for more information:
|
||||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
# https://containers.dev/guide/dependabot
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "devcontainers"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: weekly
|
||||
|
||||
156
.gitlab-ci.yml
156
.gitlab-ci.yml
@@ -1,78 +1,78 @@
|
||||
|
||||
stages: # Define the stages of the pipeline.
|
||||
- build
|
||||
#- test
|
||||
- release
|
||||
|
||||
semantic-release:
|
||||
image: node:24
|
||||
stage: release
|
||||
script:
|
||||
- apt update && apt install zip -y
|
||||
- zip -r dist.zip Web/dist/Web/browser
|
||||
- zip -r api.zip Api/build
|
||||
- npm install --save-dev @semantic-release/gitlab
|
||||
- npx semantic-release --debug
|
||||
only:
|
||||
- main
|
||||
|
||||
docker-build:
|
||||
stage: build
|
||||
image: docker:latest
|
||||
tags:
|
||||
- shared
|
||||
services:
|
||||
- name: docker:dind
|
||||
alias: docker
|
||||
variables:
|
||||
DOCKER_DRIVER: overlay2
|
||||
DOCKER_HOST: tcp://docker:2375
|
||||
DOCKER_TLS_CERTDIR: ""
|
||||
before_script:
|
||||
- docker info
|
||||
script:
|
||||
- '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|\"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 .
|
||||
- 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:${CI_PIPELINE_IID}
|
||||
only:
|
||||
- dev
|
||||
- main
|
||||
|
||||
docker-deploy:
|
||||
stage: release
|
||||
tags:
|
||||
- production
|
||||
- shell
|
||||
script:
|
||||
- echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY
|
||||
- cd deployment
|
||||
- docker compose pull
|
||||
- docker compose -f docker-compose.yaml up -d
|
||||
- docker image prune -f
|
||||
only:
|
||||
- dev
|
||||
- main
|
||||
|
||||
update_db:
|
||||
image: mcr.microsoft.com/dotnet/sdk:8.0
|
||||
stage: release
|
||||
needs: ["docker-deploy"]
|
||||
script:
|
||||
- cd Api
|
||||
- dotnet restore ./Api.csproj
|
||||
- dotnet build ./Api.csproj
|
||||
- dotnet tool install --global dotnet-ef --version 8.*
|
||||
- export PATH="$PATH:/root/.dotnet/tools"
|
||||
- dotnet-ef database update --project ./Api.csproj --startup-project ./Api.csproj
|
||||
only:
|
||||
- dev
|
||||
- main
|
||||
tags:
|
||||
- production
|
||||
- docker
|
||||
variables:
|
||||
ConnectionStrings__DefaultConnection: "Server=localhost;Database=CentrumDb;User=sa;Password=$DB_PASSWORD;TrustServerCertificate=True;"
|
||||
|
||||
stages: # Define the stages of the pipeline.
|
||||
- build
|
||||
#- test
|
||||
- release
|
||||
|
||||
semantic-release:
|
||||
image: node:24
|
||||
stage: release
|
||||
script:
|
||||
- apt update && apt install zip -y
|
||||
- zip -r dist.zip Web/dist/Web/browser
|
||||
- zip -r api.zip Api/build
|
||||
- npm install --save-dev @semantic-release/gitlab
|
||||
- npx semantic-release --debug
|
||||
only:
|
||||
- main
|
||||
|
||||
docker-build:
|
||||
stage: build
|
||||
image: docker:latest
|
||||
tags:
|
||||
- shared
|
||||
services:
|
||||
- name: docker:dind
|
||||
alias: docker
|
||||
variables:
|
||||
DOCKER_DRIVER: overlay2
|
||||
DOCKER_HOST: tcp://docker:2375
|
||||
DOCKER_TLS_CERTDIR: ""
|
||||
before_script:
|
||||
- docker info
|
||||
script:
|
||||
- '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|\"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 .
|
||||
- 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:${CI_PIPELINE_IID}
|
||||
only:
|
||||
- dev
|
||||
- main
|
||||
|
||||
docker-deploy:
|
||||
stage: release
|
||||
tags:
|
||||
- production
|
||||
- shell
|
||||
script:
|
||||
- echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY
|
||||
- cd deployment
|
||||
- docker compose pull
|
||||
- docker compose -f docker-compose.yaml up -d
|
||||
- docker image prune -f
|
||||
only:
|
||||
- dev
|
||||
- main
|
||||
|
||||
update_db:
|
||||
image: mcr.microsoft.com/dotnet/sdk:8.0
|
||||
stage: release
|
||||
needs: ["docker-deploy"]
|
||||
script:
|
||||
- cd Api
|
||||
- dotnet restore ./Api.csproj
|
||||
- dotnet build ./Api.csproj
|
||||
- dotnet tool install --global dotnet-ef --version 8.*
|
||||
- export PATH="$PATH:/root/.dotnet/tools"
|
||||
- dotnet-ef database update --project ./Api.csproj --startup-project ./Api.csproj
|
||||
only:
|
||||
- dev
|
||||
- main
|
||||
tags:
|
||||
- production
|
||||
- docker
|
||||
variables:
|
||||
ConnectionStrings__DefaultConnection: "Server=localhost;Database=CentrumDb;User=sa;Password=$DB_PASSWORD;TrustServerCertificate=True;"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
coreDump:
|
||||
enabled: false
|
||||
coreDump:
|
||||
enabled: false
|
||||
|
||||
@@ -1,37 +1,37 @@
|
||||
tasks:
|
||||
hello:
|
||||
name: Hello World
|
||||
command: |
|
||||
echo "Hello, World!"
|
||||
triggeredBy:
|
||||
- manual
|
||||
# - postEnvironmentStart
|
||||
# - postDevcontainerStart
|
||||
|
||||
services:
|
||||
example-service:
|
||||
name: Example Service
|
||||
description: Example service simulating a backend
|
||||
commands:
|
||||
start: |
|
||||
echo "Starting backend service..."
|
||||
touch /tmp/backend.started
|
||||
while true; do
|
||||
sleep 1
|
||||
date
|
||||
done
|
||||
ready: |
|
||||
if [ -f /tmp/backend.started ]; then
|
||||
echo "Backend service is ready"
|
||||
exit 0
|
||||
else
|
||||
echo "Backend service is not ready"
|
||||
exit 1
|
||||
fi
|
||||
# stop: |
|
||||
# echo "Stopping backend service..."
|
||||
# rm /tmp/backend.started
|
||||
# pkill backend
|
||||
triggeredBy:
|
||||
- postEnvironmentStart
|
||||
# - postDevcontainerStart
|
||||
tasks:
|
||||
hello:
|
||||
name: Hello World
|
||||
command: |
|
||||
echo "Hello, World!"
|
||||
triggeredBy:
|
||||
- manual
|
||||
# - postEnvironmentStart
|
||||
# - postDevcontainerStart
|
||||
|
||||
services:
|
||||
example-service:
|
||||
name: Example Service
|
||||
description: Example service simulating a backend
|
||||
commands:
|
||||
start: |
|
||||
echo "Starting backend service..."
|
||||
touch /tmp/backend.started
|
||||
while true; do
|
||||
sleep 1
|
||||
date
|
||||
done
|
||||
ready: |
|
||||
if [ -f /tmp/backend.started ]; then
|
||||
echo "Backend service is ready"
|
||||
exit 0
|
||||
else
|
||||
echo "Backend service is not ready"
|
||||
exit 1
|
||||
fi
|
||||
# stop: |
|
||||
# echo "Stopping backend service..."
|
||||
# rm /tmp/backend.started
|
||||
# pkill backend
|
||||
triggeredBy:
|
||||
- postEnvironmentStart
|
||||
# - postDevcontainerStart
|
||||
|
||||
28
.vscode/launch.json
vendored
28
.vscode/launch.json
vendored
@@ -1,15 +1,15 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"name": "Launch Chrome against localhost",
|
||||
"url": "http://localhost:4200",
|
||||
"webRoot": "${workspaceFolder}/Web"
|
||||
}
|
||||
]
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"name": "Launch Chrome against localhost",
|
||||
"url": "http://localhost:4200",
|
||||
"webRoot": "${workspaceFolder}/Web"
|
||||
}
|
||||
]
|
||||
}
|
||||
80
.vscode/tasks.json
vendored
80
.vscode/tasks.json
vendored
@@ -1,41 +1,41 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/Api/Api.sln",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary;ForceNoAlign"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "publish",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"publish",
|
||||
"${workspaceFolder}/Api/Api.sln",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary;ForceNoAlign"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "watch",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"watch",
|
||||
"run",
|
||||
"--project",
|
||||
"${workspaceFolder}/Api/Api.sln"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
}
|
||||
]
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/Api/Api.sln",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary;ForceNoAlign"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "publish",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"publish",
|
||||
"${workspaceFolder}/Api/Api.sln",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary;ForceNoAlign"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "watch",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"watch",
|
||||
"run",
|
||||
"--project",
|
||||
"${workspaceFolder}/Api/Api.sln"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
}
|
||||
]
|
||||
}
|
||||
8
Api/.gitignore
vendored
8
Api/.gitignore
vendored
@@ -1,5 +1,5 @@
|
||||
obj/
|
||||
bin/
|
||||
.vs/
|
||||
build/
|
||||
obj/
|
||||
bin/
|
||||
.vs/
|
||||
build/
|
||||
**/core
|
||||
@@ -1,70 +1,70 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Api.Models;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace Api.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
[Route("api/product")]
|
||||
public class ProductController : ControllerBase
|
||||
{
|
||||
private readonly AppDbContext _context;
|
||||
|
||||
public ProductController(AppDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
// GET: api/Product
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<IEnumerable<Product>>> GetProducts([FromQuery] int? id = null)
|
||||
{
|
||||
if (id.HasValue)
|
||||
{
|
||||
return await _context.Products
|
||||
.Where(p => p.Id == id.Value)
|
||||
.ToListAsync();
|
||||
}
|
||||
else
|
||||
return await _context.Products.ToListAsync();
|
||||
}
|
||||
|
||||
// POST: api/Product
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<Product>> PostProduct([FromBody] Product product)
|
||||
{
|
||||
_context.Products.Add(product);
|
||||
await _context.SaveChangesAsync();
|
||||
return CreatedAtAction(nameof(GetProducts), new { id = product.Id }, product);
|
||||
}
|
||||
|
||||
// PUT: api/Product/{id}
|
||||
[HttpPut("{id}")]
|
||||
public async Task<IActionResult> PutProduct(int id, [FromBody] Product product)
|
||||
{
|
||||
if (id != product.Id)
|
||||
{
|
||||
return BadRequest();
|
||||
}
|
||||
_context.Entry(product).State = EntityState.Modified;
|
||||
try
|
||||
{
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
catch (DbUpdateConcurrencyException)
|
||||
{
|
||||
if (!await _context.Products.AnyAsync(e => e.Id == id))
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
return NoContent();
|
||||
}
|
||||
}
|
||||
}
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Api.Models;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace Api.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
[Route("api/product")]
|
||||
public class ProductController : ControllerBase
|
||||
{
|
||||
private readonly AppDbContext _context;
|
||||
|
||||
public ProductController(AppDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
// GET: api/Product
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<IEnumerable<Product>>> GetProducts([FromQuery] int? id = null)
|
||||
{
|
||||
if (id.HasValue)
|
||||
{
|
||||
return await _context.Products
|
||||
.Where(p => p.Id == id.Value)
|
||||
.ToListAsync();
|
||||
}
|
||||
else
|
||||
return await _context.Products.ToListAsync();
|
||||
}
|
||||
|
||||
// POST: api/Product
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<Product>> PostProduct([FromBody] Product product)
|
||||
{
|
||||
_context.Products.Add(product);
|
||||
await _context.SaveChangesAsync();
|
||||
return CreatedAtAction(nameof(GetProducts), new { id = product.Id }, product);
|
||||
}
|
||||
|
||||
// PUT: api/Product/{id}
|
||||
[HttpPut("{id}")]
|
||||
public async Task<IActionResult> PutProduct(int id, [FromBody] Product product)
|
||||
{
|
||||
if (id != product.Id)
|
||||
{
|
||||
return BadRequest();
|
||||
}
|
||||
_context.Entry(product).State = EntityState.Modified;
|
||||
try
|
||||
{
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
catch (DbUpdateConcurrencyException)
|
||||
{
|
||||
if (!await _context.Products.AnyAsync(e => e.Id == id))
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
return NoContent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
112
Api/Migrations/20250727154636_InitialCreate.Designer.cs
generated
112
Api/Migrations/20250727154636_InitialCreate.Designer.cs
generated
@@ -1,56 +1,56 @@
|
||||
// <auto-generated />
|
||||
using Api.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Api.Migrations
|
||||
{
|
||||
[DbContext(typeof(AppDbContext))]
|
||||
[Migration("20250727154636_InitialCreate")]
|
||||
partial class InitialCreate
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "9.0.7")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Api.Models.Product", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<decimal>("Price")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Products");
|
||||
|
||||
b.HasData(
|
||||
new
|
||||
{
|
||||
Id = 1,
|
||||
Name = "Sample Product",
|
||||
Price = 9.99m
|
||||
});
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
// <auto-generated />
|
||||
using Api.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Api.Migrations
|
||||
{
|
||||
[DbContext(typeof(AppDbContext))]
|
||||
[Migration("20250727154636_InitialCreate")]
|
||||
partial class InitialCreate
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "9.0.7")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Api.Models.Product", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<decimal>("Price")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Products");
|
||||
|
||||
b.HasData(
|
||||
new
|
||||
{
|
||||
Id = 1,
|
||||
Name = "Sample Product",
|
||||
Price = 9.99m
|
||||
});
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +1,40 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Api.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class InitialCreate : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Products",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
Name = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Products", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "Products",
|
||||
columns: new[] { "Id", "Name", "Price" },
|
||||
values: new object[] { 1, "Sample Product", 9.99m });
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "Products");
|
||||
}
|
||||
}
|
||||
}
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Api.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class InitialCreate : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Products",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
Name = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Products", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "Products",
|
||||
columns: new[] { "Id", "Name", "Price" },
|
||||
values: new object[] { 1, "Sample Product", 9.99m });
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "Products");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,53 +1,53 @@
|
||||
// <auto-generated />
|
||||
using Api.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Api.Migrations
|
||||
{
|
||||
[DbContext(typeof(AppDbContext))]
|
||||
partial class AppDbContextModelSnapshot : ModelSnapshot
|
||||
{
|
||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "9.0.7")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Api.Models.Product", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<decimal>("Price")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Products");
|
||||
|
||||
b.HasData(
|
||||
new
|
||||
{
|
||||
Id = 1,
|
||||
Name = "Sample Product",
|
||||
Price = 9.99m
|
||||
});
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
// <auto-generated />
|
||||
using Api.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Api.Migrations
|
||||
{
|
||||
[DbContext(typeof(AppDbContext))]
|
||||
partial class AppDbContextModelSnapshot : ModelSnapshot
|
||||
{
|
||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "9.0.7")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Api.Models.Product", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<decimal>("Price")
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Products");
|
||||
|
||||
b.HasData(
|
||||
new
|
||||
{
|
||||
Id = 1,
|
||||
Name = "Sample Product",
|
||||
Price = 9.99m
|
||||
});
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Api.Models
|
||||
{
|
||||
public class Product
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public decimal Price { get; set; }
|
||||
}
|
||||
|
||||
public class AppDbContext : DbContext
|
||||
{
|
||||
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
|
||||
public DbSet<Product> Products { get; set; }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
// Seed data
|
||||
modelBuilder.Entity<Product>().HasData(
|
||||
new Product { Id = 1, Name = "Sample Product", Price = 9.99M }
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Api.Models
|
||||
{
|
||||
public class Product
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public decimal Price { get; set; }
|
||||
}
|
||||
|
||||
public class AppDbContext : DbContext
|
||||
{
|
||||
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
|
||||
public DbSet<Product> Products { get; set; }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
// Seed data
|
||||
modelBuilder.Entity<Product>().HasData(
|
||||
new Product { Id = 1, Name = "Sample Product", Price = 9.99M }
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
app.UseRewriter(rewriteOptions);
|
||||
|
||||
|
||||
// Serve static files from the Angular app
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
var currentDirectory = Directory.GetCurrentDirectory();
|
||||
|
||||
46
Dockerfile
46
Dockerfile
@@ -1,24 +1,24 @@
|
||||
# Build Angular Web app
|
||||
FROM node:24 AS web-build
|
||||
WORKDIR /app/web
|
||||
COPY Web/package*.json ./
|
||||
RUN npm install
|
||||
COPY Web/ ./
|
||||
RUN npm run build -- --output-path=dist/Web/browser
|
||||
|
||||
# Build .NET Api app
|
||||
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS api-build
|
||||
WORKDIR /app/api
|
||||
COPY Api/*.csproj ./
|
||||
RUN dotnet restore
|
||||
COPY Api/ ./
|
||||
RUN dotnet publish Api.csproj -c Release -o /app/api/build
|
||||
|
||||
# Final runtime image
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final
|
||||
WORKDIR /app
|
||||
COPY --from=api-build /app/api/build ./
|
||||
COPY --from=web-build /app/web/dist/Web/browser/**/* ./wwwroot/
|
||||
ENV ASPNETCORE_URLS=http://+:5000
|
||||
EXPOSE 5000
|
||||
# Build Angular Web app
|
||||
FROM node:24 AS web-build
|
||||
WORKDIR /app/web
|
||||
COPY Web/package*.json ./
|
||||
RUN npm install
|
||||
COPY Web/ ./
|
||||
RUN npm run build -- --output-path=dist/Web/browser
|
||||
|
||||
# Build .NET Api app
|
||||
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS api-build
|
||||
WORKDIR /app/api
|
||||
COPY Api/*.csproj ./
|
||||
RUN dotnet restore
|
||||
COPY Api/ ./
|
||||
RUN dotnet publish Api.csproj -c Release -o /app/api/build
|
||||
|
||||
# Final runtime image
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final
|
||||
WORKDIR /app
|
||||
COPY --from=api-build /app/api/build ./
|
||||
COPY --from=web-build /app/web/dist/Web/browser/**/* ./wwwroot/
|
||||
ENV ASPNETCORE_URLS=http://+:5000
|
||||
EXPOSE 5000
|
||||
ENTRYPOINT ["dotnet", "Api.dll"]
|
||||
186
README.md
186
README.md
@@ -1,93 +1,93 @@
|
||||
# Centrum
|
||||
|
||||

|
||||
[](https://gitlab.lesko.me/marek/centrum/-/commits/main)
|
||||
## Getting started
|
||||
|
||||
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)!
|
||||
|
||||
## 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
|
||||
- [ ] [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
|
||||
git remote add origin https://gitlab.lesko.me/marek/centrum.git
|
||||
git branch -M main
|
||||
git push -uf origin main
|
||||
```
|
||||
|
||||
## Integrate with your tools
|
||||
|
||||
- [ ] [Set up project integrations](https://gitlab.lesko.me/marek/centrum/-/settings/integrations)
|
||||
|
||||
## Collaborate with your team
|
||||
|
||||
- [ ] [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)
|
||||
- [ ] [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/)
|
||||
- [ ] [Set auto-merge](https://docs.gitlab.com/user/project/merge_requests/auto_merge/)
|
||||
|
||||
## Test and Deploy
|
||||
|
||||
Use the built-in continuous integration in GitLab.
|
||||
|
||||
- [ ] [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/)
|
||||
- [ ] [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/)
|
||||
- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
|
||||
|
||||
***
|
||||
|
||||
# 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.
|
||||
|
||||
## 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.
|
||||
|
||||
## Name
|
||||
Choose a self-explaining name for your project.
|
||||
|
||||
## 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.
|
||||
|
||||
## 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.
|
||||
|
||||
## 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.
|
||||
|
||||
## 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.
|
||||
|
||||
## 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.
|
||||
|
||||
## 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.
|
||||
|
||||
## Roadmap
|
||||
If you have ideas for releases in the future, it is a good idea to list them in the README.
|
||||
|
||||
## Contributing
|
||||
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.
|
||||
|
||||
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
|
||||
Show your appreciation to those who have contributed to the project.
|
||||
|
||||
## License
|
||||
For open source projects, say how it is licensed.
|
||||
|
||||
## 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.
|
||||
# Centrum
|
||||
|
||||

|
||||
[](https://gitlab.lesko.me/marek/centrum/-/commits/main)
|
||||
## Getting started
|
||||
|
||||
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)!
|
||||
|
||||
## 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
|
||||
- [ ] [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
|
||||
git remote add origin https://gitlab.lesko.me/marek/centrum.git
|
||||
git branch -M main
|
||||
git push -uf origin main
|
||||
```
|
||||
|
||||
## Integrate with your tools
|
||||
|
||||
- [ ] [Set up project integrations](https://gitlab.lesko.me/marek/centrum/-/settings/integrations)
|
||||
|
||||
## Collaborate with your team
|
||||
|
||||
- [ ] [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)
|
||||
- [ ] [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/)
|
||||
- [ ] [Set auto-merge](https://docs.gitlab.com/user/project/merge_requests/auto_merge/)
|
||||
|
||||
## Test and Deploy
|
||||
|
||||
Use the built-in continuous integration in GitLab.
|
||||
|
||||
- [ ] [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/)
|
||||
- [ ] [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/)
|
||||
- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
|
||||
|
||||
***
|
||||
|
||||
# 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.
|
||||
|
||||
## 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.
|
||||
|
||||
## Name
|
||||
Choose a self-explaining name for your project.
|
||||
|
||||
## 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.
|
||||
|
||||
## 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.
|
||||
|
||||
## 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.
|
||||
|
||||
## 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.
|
||||
|
||||
## 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.
|
||||
|
||||
## 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.
|
||||
|
||||
## Roadmap
|
||||
If you have ideas for releases in the future, it is a good idea to list them in the README.
|
||||
|
||||
## Contributing
|
||||
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.
|
||||
|
||||
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
|
||||
Show your appreciation to those who have contributed to the project.
|
||||
|
||||
## License
|
||||
For open source projects, say how it is licensed.
|
||||
|
||||
## 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.
|
||||
|
||||
2
Tests/.gitignore
vendored
2
Tests/.gitignore
vendored
@@ -1,2 +1,2 @@
|
||||
obj/
|
||||
obj/
|
||||
bin/
|
||||
@@ -1,38 +1,38 @@
|
||||
namespace Tests.Tests
|
||||
{
|
||||
public class IntegrationTest1
|
||||
{
|
||||
// Instructions:
|
||||
// 1. Add a project reference to the target AppHost project, e.g.:
|
||||
//
|
||||
// <ItemGroup>
|
||||
// <ProjectReference Include="../MyAspireApp.AppHost/MyAspireApp.AppHost.csproj" />
|
||||
// </ItemGroup>
|
||||
//
|
||||
// 2. Uncomment the following example test and update 'Projects.MyAspireApp_AppHost' to match your AppHost project:
|
||||
//
|
||||
// [Fact]
|
||||
// public async Task GetWebResourceRootReturnsOkStatusCode()
|
||||
// {
|
||||
// // Arrange
|
||||
// var appHost = await DistributedApplicationTestingBuilder.CreateAsync<Projects.MyAspireApp_AppHost>();
|
||||
// appHost.Services.ConfigureHttpClientDefaults(clientBuilder =>
|
||||
// {
|
||||
// clientBuilder.AddStandardResilienceHandler();
|
||||
// });
|
||||
// // To output logs to the xUnit.net ITestOutputHelper, consider adding a package from https://www.nuget.org/packages?q=xunit+logging
|
||||
//
|
||||
// await using var app = await appHost.BuildAsync();
|
||||
// var resourceNotificationService = app.Services.GetRequiredService<ResourceNotificationService>();
|
||||
// await app.StartAsync();
|
||||
|
||||
// // Act
|
||||
// var httpClient = app.CreateHttpClient("webfrontend");
|
||||
// await resourceNotificationService.WaitForResourceAsync("webfrontend", KnownResourceStates.Running).WaitAsync(TimeSpan.FromSeconds(30));
|
||||
// var response = await httpClient.GetAsync("/");
|
||||
|
||||
// // Assert
|
||||
// Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
// }
|
||||
}
|
||||
}
|
||||
namespace Tests.Tests
|
||||
{
|
||||
public class IntegrationTest1
|
||||
{
|
||||
// Instructions:
|
||||
// 1. Add a project reference to the target AppHost project, e.g.:
|
||||
//
|
||||
// <ItemGroup>
|
||||
// <ProjectReference Include="../MyAspireApp.AppHost/MyAspireApp.AppHost.csproj" />
|
||||
// </ItemGroup>
|
||||
//
|
||||
// 2. Uncomment the following example test and update 'Projects.MyAspireApp_AppHost' to match your AppHost project:
|
||||
//
|
||||
// [Fact]
|
||||
// public async Task GetWebResourceRootReturnsOkStatusCode()
|
||||
// {
|
||||
// // Arrange
|
||||
// var appHost = await DistributedApplicationTestingBuilder.CreateAsync<Projects.MyAspireApp_AppHost>();
|
||||
// appHost.Services.ConfigureHttpClientDefaults(clientBuilder =>
|
||||
// {
|
||||
// clientBuilder.AddStandardResilienceHandler();
|
||||
// });
|
||||
// // To output logs to the xUnit.net ITestOutputHelper, consider adding a package from https://www.nuget.org/packages?q=xunit+logging
|
||||
//
|
||||
// await using var app = await appHost.BuildAsync();
|
||||
// var resourceNotificationService = app.Services.GetRequiredService<ResourceNotificationService>();
|
||||
// await app.StartAsync();
|
||||
|
||||
// // Act
|
||||
// var httpClient = app.CreateHttpClient("webfrontend");
|
||||
// await resourceNotificationService.WaitForResourceAsync("webfrontend", KnownResourceStates.Running).WaitAsync(TimeSpan.FromSeconds(30));
|
||||
// var response = await httpClient.GetAsync("/");
|
||||
|
||||
// // Assert
|
||||
// Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Aspire.Hosting.Testing" Version="9.3.1" />
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="System.Net" />
|
||||
<Using Include="Microsoft.Extensions.DependencyInjection" />
|
||||
<Using Include="Aspire.Hosting.ApplicationModel" />
|
||||
<Using Include="Aspire.Hosting.Testing" />
|
||||
<Using Include="Xunit" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Aspire.Hosting.Testing" Version="9.3.1" />
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="System.Net" />
|
||||
<Using Include="Microsoft.Extensions.DependencyInjection" />
|
||||
<Using Include="Aspire.Hosting.ApplicationModel" />
|
||||
<Using Include="Aspire.Hosting.Testing" />
|
||||
<Using Include="Xunit" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
# Editor configuration, see https://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.ts]
|
||||
quote_type = single
|
||||
ij_typescript_use_double_quotes = false
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
||||
# Editor configuration, see https://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.ts]
|
||||
quote_type = single
|
||||
ij_typescript_use_double_quotes = false
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
84
Web/.gitignore
vendored
84
Web/.gitignore
vendored
@@ -1,42 +1,42 @@
|
||||
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
|
||||
|
||||
# Compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
/bazel-out
|
||||
|
||||
# Node
|
||||
/node_modules
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
|
||||
# IDEs and editors
|
||||
.idea/
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# Visual Studio Code
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
.history/*
|
||||
|
||||
# Miscellaneous
|
||||
/.angular/cache
|
||||
.sass-cache/
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# System files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
|
||||
|
||||
# Compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
/bazel-out
|
||||
|
||||
# Node
|
||||
/node_modules
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
|
||||
# IDEs and editors
|
||||
.idea/
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# Visual Studio Code
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
.history/*
|
||||
|
||||
# Miscellaneous
|
||||
/.angular/cache
|
||||
.sass-cache/
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# System files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
8
Web/.vscode/extensions.json
vendored
8
Web/.vscode/extensions.json
vendored
@@ -1,4 +1,4 @@
|
||||
{
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
|
||||
"recommendations": ["angular.ng-template"]
|
||||
}
|
||||
{
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846
|
||||
"recommendations": ["angular.ng-template"]
|
||||
}
|
||||
|
||||
42
Web/.vscode/launch.json
vendored
42
Web/.vscode/launch.json
vendored
@@ -1,21 +1,21 @@
|
||||
{
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "ng serve",
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "npm: start",
|
||||
"url": "http://localhost:4200/",
|
||||
"webRoot": "${workspaceFolder}/Web",
|
||||
},
|
||||
{
|
||||
"name": "ng test",
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "npm: test",
|
||||
"url": "http://localhost:9876/debug.html"
|
||||
}
|
||||
]
|
||||
}
|
||||
{
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "ng serve",
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "npm: start",
|
||||
"url": "http://localhost:4200/",
|
||||
"webRoot": "${workspaceFolder}/Web",
|
||||
},
|
||||
{
|
||||
"name": "ng test",
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "npm: test",
|
||||
"url": "http://localhost:9876/debug.html"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
84
Web/.vscode/tasks.json
vendored
84
Web/.vscode/tasks.json
vendored
@@ -1,42 +1,42 @@
|
||||
{
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "start",
|
||||
"isBackground": true,
|
||||
"problemMatcher": {
|
||||
"owner": "typescript",
|
||||
"pattern": "$tsc",
|
||||
"background": {
|
||||
"activeOnStart": true,
|
||||
"beginsPattern": {
|
||||
"regexp": "(.*?)"
|
||||
},
|
||||
"endsPattern": {
|
||||
"regexp": "bundle generation complete"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "test",
|
||||
"isBackground": true,
|
||||
"problemMatcher": {
|
||||
"owner": "typescript",
|
||||
"pattern": "$tsc",
|
||||
"background": {
|
||||
"activeOnStart": true,
|
||||
"beginsPattern": {
|
||||
"regexp": "(.*?)"
|
||||
},
|
||||
"endsPattern": {
|
||||
"regexp": "bundle generation complete"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
{
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "start",
|
||||
"isBackground": true,
|
||||
"problemMatcher": {
|
||||
"owner": "typescript",
|
||||
"pattern": "$tsc",
|
||||
"background": {
|
||||
"activeOnStart": true,
|
||||
"beginsPattern": {
|
||||
"regexp": "(.*?)"
|
||||
},
|
||||
"endsPattern": {
|
||||
"regexp": "bundle generation complete"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "test",
|
||||
"isBackground": true,
|
||||
"problemMatcher": {
|
||||
"owner": "typescript",
|
||||
"pattern": "$tsc",
|
||||
"background": {
|
||||
"activeOnStart": true,
|
||||
"beginsPattern": {
|
||||
"regexp": "(.*?)"
|
||||
},
|
||||
"endsPattern": {
|
||||
"regexp": "bundle generation complete"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
118
Web/README.md
118
Web/README.md
@@ -1,59 +1,59 @@
|
||||
# Web
|
||||
|
||||
This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 20.0.6.
|
||||
|
||||
## Development server
|
||||
|
||||
To start a local development server, run:
|
||||
|
||||
```bash
|
||||
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.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
|
||||
|
||||
```bash
|
||||
ng generate component component-name
|
||||
```
|
||||
|
||||
For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
|
||||
|
||||
```bash
|
||||
ng generate --help
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
To build the project run:
|
||||
|
||||
```bash
|
||||
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.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
|
||||
|
||||
```bash
|
||||
ng test
|
||||
```
|
||||
|
||||
## Running end-to-end tests
|
||||
|
||||
For end-to-end (e2e) testing, run:
|
||||
|
||||
```bash
|
||||
ng e2e
|
||||
```
|
||||
|
||||
Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
|
||||
|
||||
## 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.
|
||||
# Web
|
||||
|
||||
This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 20.0.6.
|
||||
|
||||
## Development server
|
||||
|
||||
To start a local development server, run:
|
||||
|
||||
```bash
|
||||
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.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
|
||||
|
||||
```bash
|
||||
ng generate component component-name
|
||||
```
|
||||
|
||||
For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
|
||||
|
||||
```bash
|
||||
ng generate --help
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
To build the project run:
|
||||
|
||||
```bash
|
||||
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.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
|
||||
|
||||
```bash
|
||||
ng test
|
||||
```
|
||||
|
||||
## Running end-to-end tests
|
||||
|
||||
For end-to-end (e2e) testing, run:
|
||||
|
||||
```bash
|
||||
ng e2e
|
||||
```
|
||||
|
||||
Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
|
||||
|
||||
## 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.
|
||||
|
||||
198
Web/angular.json
198
Web/angular.json
@@ -1,100 +1,100 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"Web": {
|
||||
"projectType": "application",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"style": "scss"
|
||||
}
|
||||
},
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular/build:application",
|
||||
"options": {
|
||||
"browser": "src/main.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": [
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "public"
|
||||
}
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.scss"
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "500kB",
|
||||
"maximumError": "1MB"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "4kB",
|
||||
"maximumError": "8kB"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"optimization": false,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular/build:dev-server",
|
||||
"options": {
|
||||
"allowedHosts": [
|
||||
"localhost",
|
||||
"4200--0197f0a3-fef1-7776-b920-71d5d9c3d787.us01.gitpod.dev"
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"buildTarget": "Web:build:production"
|
||||
},
|
||||
"development": {
|
||||
"buildTarget": "Web:build:development"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular/build:extract-i18n"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular/build:karma",
|
||||
"options": {
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": [
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "public"
|
||||
}
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.scss"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cli": {
|
||||
"analytics": false
|
||||
}
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"Web": {
|
||||
"projectType": "application",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"style": "scss"
|
||||
}
|
||||
},
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular/build:application",
|
||||
"options": {
|
||||
"browser": "src/main.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": [
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "public"
|
||||
}
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.scss"
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "500kB",
|
||||
"maximumError": "1MB"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "4kB",
|
||||
"maximumError": "8kB"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"optimization": false,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular/build:dev-server",
|
||||
"options": {
|
||||
"allowedHosts": [
|
||||
"localhost",
|
||||
"4200--0197f0a3-fef1-7776-b920-71d5d9c3d787.us01.gitpod.dev"
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"buildTarget": "Web:build:production"
|
||||
},
|
||||
"development": {
|
||||
"buildTarget": "Web:build:development"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular/build:extract-i18n"
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular/build:karma",
|
||||
"options": {
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": [
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "public"
|
||||
}
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.scss"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cli": {
|
||||
"analytics": false
|
||||
}
|
||||
}
|
||||
17828
Web/package-lock.json
generated
17828
Web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,46 +1,46 @@
|
||||
{
|
||||
"name": "web",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve --host 0.0.0.0",
|
||||
"build": "ng build --configuration=production",
|
||||
"watch": "ng build --watch --configuration development",
|
||||
"test": "ng test"
|
||||
},
|
||||
"prettier": {
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.html",
|
||||
"options": {
|
||||
"parser": "angular"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/common": "^20.0.0",
|
||||
"@angular/compiler": "^20.0.0",
|
||||
"@angular/core": "^20.0.0",
|
||||
"@angular/forms": "^20.0.0",
|
||||
"@angular/platform-browser": "^20.0.0",
|
||||
"@angular/router": "^20.0.0",
|
||||
"angular-oauth2-oidc": "^20.0.2",
|
||||
"rxjs": "~7.8.0",
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/build": "^20.0.6",
|
||||
"@angular/cli": "^20.0.6",
|
||||
"@angular/compiler-cli": "^20.0.0",
|
||||
"@types/jasmine": "~5.1.0",
|
||||
"jasmine-core": "~5.7.0",
|
||||
"karma": "~6.4.0",
|
||||
"karma-chrome-launcher": "~3.2.0",
|
||||
"karma-coverage": "~2.2.0",
|
||||
"karma-jasmine": "~5.1.0",
|
||||
"karma-jasmine-html-reporter": "~2.1.0",
|
||||
"typescript": "~5.8.2"
|
||||
}
|
||||
}
|
||||
{
|
||||
"name": "web",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve --host 0.0.0.0",
|
||||
"build": "ng build --configuration=production",
|
||||
"watch": "ng build --watch --configuration development",
|
||||
"test": "ng test"
|
||||
},
|
||||
"prettier": {
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.html",
|
||||
"options": {
|
||||
"parser": "angular"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/common": "^20.0.0",
|
||||
"@angular/compiler": "^20.0.0",
|
||||
"@angular/core": "^20.0.0",
|
||||
"@angular/forms": "^20.0.0",
|
||||
"@angular/platform-browser": "^20.0.0",
|
||||
"@angular/router": "^20.0.0",
|
||||
"angular-oauth2-oidc": "^20.0.2",
|
||||
"rxjs": "~7.8.0",
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/build": "^20.0.6",
|
||||
"@angular/cli": "^20.0.6",
|
||||
"@angular/compiler-cli": "^20.0.0",
|
||||
"@types/jasmine": "~5.1.0",
|
||||
"jasmine-core": "~5.7.0",
|
||||
"karma": "~6.4.0",
|
||||
"karma-chrome-launcher": "~3.2.0",
|
||||
"karma-coverage": "~2.2.0",
|
||||
"karma-jasmine": "~5.1.0",
|
||||
"karma-jasmine-html-reporter": "~2.1.0",
|
||||
"typescript": "~5.8.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"apiEndpoint": "https://localhost:5001"
|
||||
{
|
||||
"apiEndpoint": "https://localhost:5001"
|
||||
}
|
||||
@@ -1,34 +1,34 @@
|
||||
import { ApplicationConfig, inject, provideAppInitializer, provideBrowserGlobalErrorListeners, provideZonelessChangeDetection } from '@angular/core';
|
||||
import { provideRouter } from '@angular/router';
|
||||
|
||||
import { routes } from './app.routes';
|
||||
import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
|
||||
import { DefaultOAuthInterceptor, provideOAuthClient } from 'angular-oauth2-oidc';
|
||||
import { AppConfigService } from './services/config.service';
|
||||
import { ApiEndpointInterceptor } from './services/http.interceptor';
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
provideBrowserGlobalErrorListeners(),
|
||||
provideZonelessChangeDetection(),
|
||||
provideRouter(routes),
|
||||
provideAppInitializer(() => inject(AppConfigService).loadConfig()),
|
||||
{
|
||||
provide: HTTP_INTERCEPTORS,
|
||||
useClass: DefaultOAuthInterceptor,
|
||||
multi: true,
|
||||
},
|
||||
{
|
||||
provide: HTTP_INTERCEPTORS,
|
||||
useClass: ApiEndpointInterceptor,
|
||||
multi: true,
|
||||
},
|
||||
provideHttpClient(withInterceptorsFromDi()),
|
||||
provideOAuthClient({
|
||||
resourceServer: {
|
||||
allowedUrls: ['http://localhost:5000', 'https://localhost:5001', 'https://centrum.lesko.me','https://beta.e-dias.sk/'],
|
||||
sendAccessToken: true,
|
||||
},
|
||||
}),
|
||||
]
|
||||
};
|
||||
import { ApplicationConfig, inject, provideAppInitializer, provideBrowserGlobalErrorListeners, provideZonelessChangeDetection } from '@angular/core';
|
||||
import { provideRouter } from '@angular/router';
|
||||
|
||||
import { routes } from './app.routes';
|
||||
import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
|
||||
import { DefaultOAuthInterceptor, provideOAuthClient } from 'angular-oauth2-oidc';
|
||||
import { AppConfigService } from './services/config.service';
|
||||
import { ApiEndpointInterceptor } from './services/http.interceptor';
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
provideBrowserGlobalErrorListeners(),
|
||||
provideZonelessChangeDetection(),
|
||||
provideRouter(routes),
|
||||
provideAppInitializer(() => inject(AppConfigService).loadConfig()),
|
||||
{
|
||||
provide: HTTP_INTERCEPTORS,
|
||||
useClass: DefaultOAuthInterceptor,
|
||||
multi: true,
|
||||
},
|
||||
{
|
||||
provide: HTTP_INTERCEPTORS,
|
||||
useClass: ApiEndpointInterceptor,
|
||||
multi: true,
|
||||
},
|
||||
provideHttpClient(withInterceptorsFromDi()),
|
||||
provideOAuthClient({
|
||||
resourceServer: {
|
||||
allowedUrls: ['http://localhost:5000', 'https://localhost:5001', 'https://centrum.lesko.me','https://beta.e-dias.sk/'],
|
||||
sendAccessToken: true,
|
||||
},
|
||||
}),
|
||||
]
|
||||
};
|
||||
|
||||
@@ -1 +1 @@
|
||||
<router-outlet />
|
||||
<router-outlet />
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { CanActivateFn } from '@angular/router';
|
||||
import { inject } from '@angular/core';
|
||||
import { OAuthService } from 'angular-oauth2-oidc';
|
||||
|
||||
|
||||
export const authGuard: CanActivateFn = (route, state) => {
|
||||
const authService = inject(OAuthService);
|
||||
return authService.hasValidAccessToken(); // returns boolean, Promise, or Observable
|
||||
};
|
||||
import { CanActivateFn } from '@angular/router';
|
||||
import { inject } from '@angular/core';
|
||||
import { OAuthService } from 'angular-oauth2-oidc';
|
||||
|
||||
|
||||
export const authGuard: CanActivateFn = (route, state) => {
|
||||
const authService = inject(OAuthService);
|
||||
return authService.hasValidAccessToken(); // returns boolean, Promise, or Observable
|
||||
};
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import { Routes } from '@angular/router';
|
||||
import { Login } from './login/login';
|
||||
import { authGuard } from './app.route.guard';
|
||||
|
||||
export const routes: Routes = [
|
||||
{
|
||||
path: 'login',
|
||||
component: Login,
|
||||
},
|
||||
{
|
||||
path: 'content',
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
loadComponent: () => import('./content/content').then(m => m.Content),
|
||||
canActivate: [authGuard],
|
||||
}
|
||||
],
|
||||
}
|
||||
];
|
||||
import { Routes } from '@angular/router';
|
||||
import { Login } from './login/login';
|
||||
import { authGuard } from './app.route.guard';
|
||||
|
||||
export const routes: Routes = [
|
||||
{
|
||||
path: 'login',
|
||||
component: Login,
|
||||
},
|
||||
{
|
||||
path: 'content',
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
loadComponent: () => import('./content/content').then(m => m.Content),
|
||||
canActivate: [authGuard],
|
||||
}
|
||||
],
|
||||
}
|
||||
];
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import { provideZonelessChangeDetection } from '@angular/core';
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { App } from './app';
|
||||
|
||||
describe('App', () => {
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [App],
|
||||
providers: [provideZonelessChangeDetection()]
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
it('should create the app', () => {
|
||||
const fixture = TestBed.createComponent(App);
|
||||
const app = fixture.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should render title', () => {
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
const compiled = fixture.nativeElement as HTMLElement;
|
||||
expect(compiled.querySelector('h1')?.textContent).toContain('Hello, Web');
|
||||
});
|
||||
});
|
||||
import { provideZonelessChangeDetection } from '@angular/core';
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { App } from './app';
|
||||
|
||||
describe('App', () => {
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [App],
|
||||
providers: [provideZonelessChangeDetection()]
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
it('should create the app', () => {
|
||||
const fixture = TestBed.createComponent(App);
|
||||
const app = fixture.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should render title', () => {
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
const compiled = fixture.nativeElement as HTMLElement;
|
||||
expect(compiled.querySelector('h1')?.textContent).toContain('Hello, Web');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
import { HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||
import { APP_INITIALIZER, Component, inject, OnInit, provideAppInitializer } from '@angular/core';
|
||||
import { Router, RouterOutlet } from '@angular/router';
|
||||
import { DefaultOAuthInterceptor, OAuthService } from 'angular-oauth2-oidc';
|
||||
import { AppConfigService } from './services/config.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
imports: [RouterOutlet],
|
||||
providers: [
|
||||
OAuthService,
|
||||
],
|
||||
templateUrl: './app.html',
|
||||
styleUrl: './app.scss'
|
||||
})
|
||||
export class App implements OnInit {
|
||||
protected title = 'Web';
|
||||
constructor(private readonly as: OAuthService, private readonly router: Router) {
|
||||
this.as.configure({
|
||||
issuer: 'https://identity.lesko.me',
|
||||
redirectUri: window.location.origin + '/login',
|
||||
clientId: '21131567-fea1-42a2-8907-21abd874eff8',
|
||||
scope: 'openid profile email',
|
||||
responseType: 'code',
|
||||
timeoutFactor: 0.01,
|
||||
});
|
||||
}
|
||||
ngOnInit(): void {
|
||||
this.as.loadDiscoveryDocumentAndLogin().then(() => this.router.navigate(['login']));
|
||||
}
|
||||
}
|
||||
import { HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||
import { APP_INITIALIZER, Component, inject, OnInit, provideAppInitializer } from '@angular/core';
|
||||
import { Router, RouterOutlet } from '@angular/router';
|
||||
import { DefaultOAuthInterceptor, OAuthService } from 'angular-oauth2-oidc';
|
||||
import { AppConfigService } from './services/config.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
imports: [RouterOutlet],
|
||||
providers: [
|
||||
OAuthService,
|
||||
],
|
||||
templateUrl: './app.html',
|
||||
styleUrl: './app.scss'
|
||||
})
|
||||
export class App implements OnInit {
|
||||
protected title = 'Web';
|
||||
constructor(private readonly as: OAuthService, private readonly router: Router) {
|
||||
this.as.configure({
|
||||
issuer: 'https://identity.lesko.me',
|
||||
redirectUri: window.location.origin + '/login',
|
||||
clientId: '21131567-fea1-42a2-8907-21abd874eff8',
|
||||
scope: 'openid profile email',
|
||||
responseType: 'code',
|
||||
timeoutFactor: 0.01,
|
||||
});
|
||||
}
|
||||
ngOnInit(): void {
|
||||
this.as.loadDiscoveryDocumentAndLogin().then(() => this.router.navigate(['login']));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { Content } from './content';
|
||||
|
||||
describe('Content', () => {
|
||||
let component: Content;
|
||||
let fixture: ComponentFixture<Content>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [Content]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(Content);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { Content } from './content';
|
||||
|
||||
describe('Content', () => {
|
||||
let component: Content;
|
||||
let fixture: ComponentFixture<Content>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [Content]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(Content);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import { JsonPipe } from '@angular/common';
|
||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
import { Component, isDevMode, signal } from '@angular/core';
|
||||
import { OAuthService } from 'angular-oauth2-oidc';
|
||||
import { AppConfigService } from '../services/config.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-content',
|
||||
imports: [JsonPipe],
|
||||
templateUrl: './content.html',
|
||||
styleUrl: './content.scss'
|
||||
})
|
||||
export class Content {
|
||||
data = signal({});
|
||||
|
||||
constructor(httpClient: HttpClient, readonly as: OAuthService, readonly cs: AppConfigService) {
|
||||
httpClient.get('/api/product')
|
||||
.subscribe(data => {
|
||||
this.data.set(data);
|
||||
});
|
||||
}
|
||||
}
|
||||
import { JsonPipe } from '@angular/common';
|
||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
import { Component, isDevMode, signal } from '@angular/core';
|
||||
import { OAuthService } from 'angular-oauth2-oidc';
|
||||
import { AppConfigService } from '../services/config.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-content',
|
||||
imports: [JsonPipe],
|
||||
templateUrl: './content.html',
|
||||
styleUrl: './content.scss'
|
||||
})
|
||||
export class Content {
|
||||
data = signal({});
|
||||
|
||||
constructor(httpClient: HttpClient, readonly as: OAuthService, readonly cs: AppConfigService) {
|
||||
httpClient.get('/api/product')
|
||||
.subscribe(data => {
|
||||
this.data.set(data);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
|
||||
|
||||
Logging in...
|
||||
@@ -1,23 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { Login } from './login';
|
||||
|
||||
describe('Login', () => {
|
||||
let component: Login;
|
||||
let fixture: ComponentFixture<Login>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [Login]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(Login);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { Login } from './login';
|
||||
|
||||
describe('Login', () => {
|
||||
let component: Login;
|
||||
let fixture: ComponentFixture<Login>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [Login]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(Login);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { OAuthService } from 'angular-oauth2-oidc';
|
||||
|
||||
@Component({
|
||||
selector: 'app-login',
|
||||
templateUrl: './login.html',
|
||||
styleUrl: './login.scss'
|
||||
})
|
||||
export class Login implements OnInit {
|
||||
|
||||
constructor(readonly as: OAuthService, readonly router: Router) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
if (this.as.hasValidAccessToken() && this.as.hasValidIdToken()) {
|
||||
this.getUserInfo();
|
||||
} else {
|
||||
this.as.events.subscribe(event => {
|
||||
if (event.type === 'token_received')
|
||||
if (this.as.hasValidIdToken()) {
|
||||
this.getUserInfo();
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
getUserInfo(): void {
|
||||
this.as.loadUserProfile().then(value => {
|
||||
console.log('User profile loaded:', value);
|
||||
this.router.navigate(['/content']);
|
||||
});
|
||||
}
|
||||
}
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { OAuthService } from 'angular-oauth2-oidc';
|
||||
|
||||
@Component({
|
||||
selector: 'app-login',
|
||||
templateUrl: './login.html',
|
||||
styleUrl: './login.scss'
|
||||
})
|
||||
export class Login implements OnInit {
|
||||
|
||||
constructor(readonly as: OAuthService, readonly router: Router) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
if (this.as.hasValidAccessToken() && this.as.hasValidIdToken()) {
|
||||
this.getUserInfo();
|
||||
} else {
|
||||
this.as.events.subscribe(event => {
|
||||
if (event.type === 'token_received')
|
||||
if (this.as.hasValidIdToken()) {
|
||||
this.getUserInfo();
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
getUserInfo(): void {
|
||||
this.as.loadUserProfile().then(value => {
|
||||
console.log('User profile loaded:', value);
|
||||
this.router.navigate(['/content']);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,31 +1,31 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AppConfigService {
|
||||
private config: any;
|
||||
|
||||
public loaded: boolean = false;
|
||||
|
||||
constructor() { }
|
||||
|
||||
loadConfig(): Observable<any> {
|
||||
return new Observable(observer => {
|
||||
fetch('/config.json')
|
||||
.then(async response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`Could not load config.json: ${response.statusText}`);
|
||||
}
|
||||
this.config = await response.json();
|
||||
this.loaded = true;
|
||||
observer.next(this.config);
|
||||
observer.complete();
|
||||
})
|
||||
.catch(error => observer.error(error));
|
||||
});
|
||||
}
|
||||
|
||||
get setting() {
|
||||
return this.config;
|
||||
}
|
||||
}
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AppConfigService {
|
||||
private config: any;
|
||||
|
||||
public loaded: boolean = false;
|
||||
|
||||
constructor() { }
|
||||
|
||||
loadConfig(): Observable<any> {
|
||||
return new Observable(observer => {
|
||||
fetch('/config.json')
|
||||
.then(async response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`Could not load config.json: ${response.statusText}`);
|
||||
}
|
||||
this.config = await response.json();
|
||||
this.loaded = true;
|
||||
observer.next(this.config);
|
||||
observer.complete();
|
||||
})
|
||||
.catch(error => observer.error(error));
|
||||
});
|
||||
}
|
||||
|
||||
get setting() {
|
||||
return this.config;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs';
|
||||
import { AppConfigService } from './config.service';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ApiEndpointInterceptor implements HttpInterceptor {
|
||||
constructor(private readonly configService: AppConfigService) { }
|
||||
|
||||
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||
return this.prependUrl(req, next);
|
||||
}
|
||||
|
||||
prependUrl(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||
const apiEndpoint = this.configService.setting.apiEndpoint;
|
||||
if (apiEndpoint === undefined || !this.configService.loaded)
|
||||
throw new Error('API endpoint is not defined or config not loaded');
|
||||
|
||||
const isRelative = !/^https?:\/\//i.test(req.url);
|
||||
const url = isRelative ? `${apiEndpoint.replace(/\/$/, '')}/${req.url.replace(/^\//, '')}` : req.url;
|
||||
const cloned = req.clone({ url });
|
||||
console.trace('ApiEndpointInterceptor hit:', url);
|
||||
return next.handle(cloned);
|
||||
}
|
||||
}
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs';
|
||||
import { AppConfigService } from './config.service';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ApiEndpointInterceptor implements HttpInterceptor {
|
||||
constructor(private readonly configService: AppConfigService) { }
|
||||
|
||||
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||
return this.prependUrl(req, next);
|
||||
}
|
||||
|
||||
prependUrl(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||
const apiEndpoint = this.configService.setting.apiEndpoint;
|
||||
if (apiEndpoint === undefined || !this.configService.loaded)
|
||||
throw new Error('API endpoint is not defined or config not loaded');
|
||||
|
||||
const isRelative = !/^https?:\/\//i.test(req.url);
|
||||
const url = isRelative ? `${apiEndpoint.replace(/\/$/, '')}/${req.url.replace(/^\//, '')}` : req.url;
|
||||
const cloned = req.clone({ url });
|
||||
console.trace('ApiEndpointInterceptor hit:', url);
|
||||
return next.handle(cloned);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Web</title>
|
||||
<base href="/">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
</html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Web</title>
|
||||
<base href="/">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { bootstrapApplication } from '@angular/platform-browser';
|
||||
import { appConfig } from './app/app.config';
|
||||
import { App } from './app/app';
|
||||
|
||||
bootstrapApplication(App, appConfig)
|
||||
.catch((err) => console.error(err));
|
||||
import { bootstrapApplication } from '@angular/platform-browser';
|
||||
import { appConfig } from './app/app.config';
|
||||
import { App } from './app/app';
|
||||
|
||||
bootstrapApplication(App, appConfig)
|
||||
.catch((err) => console.error(err));
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# Editor configuration, see https://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.ts]
|
||||
quote_type = single
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
||||
# Editor configuration, see https://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.ts]
|
||||
quote_type = single
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
84
Web/themes/modernize/.gitignore
vendored
84
Web/themes/modernize/.gitignore
vendored
@@ -1,42 +1,42 @@
|
||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# Compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
/bazel-out
|
||||
|
||||
# Node
|
||||
/node_modules
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
|
||||
# IDEs and editors
|
||||
.idea/
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# Visual Studio Code
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
.history/*
|
||||
|
||||
# Miscellaneous
|
||||
/.angular/cache
|
||||
.sass-cache/
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# System files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# Compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
/bazel-out
|
||||
|
||||
# Node
|
||||
/node_modules
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
|
||||
# IDEs and editors
|
||||
.idea/
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# Visual Studio Code
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
.history/*
|
||||
|
||||
# Miscellaneous
|
||||
/.angular/cache
|
||||
.sass-cache/
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# System files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
# Modernize-Angular-pro
|
||||
Modernize Angular Admin Dashboard
|
||||
# Modernize-Angular-pro
|
||||
Modernize Angular Admin Dashboard
|
||||
|
||||
@@ -1,96 +1,96 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"Modernize": {
|
||||
"projectType": "application",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"style": "scss"
|
||||
}
|
||||
},
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"allowedCommonJsDependencies": ["apexcharts", "bezier-easing", "moment"],
|
||||
"outputPath": "dist/Modernize",
|
||||
"index": "src/index.html",
|
||||
"main": "src/main.ts",
|
||||
"polyfills": ["zone.js"],
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": ["src/favicon.ico", "src/assets"],
|
||||
"styles": ["src/styles.scss", "src/assets/scss/style.scss"],
|
||||
"scripts": []
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "12mb",
|
||||
"maximumError": "12mb"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "12mb",
|
||||
"maximumError": "12mb"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"buildOptimizer": false,
|
||||
"optimization": false,
|
||||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true,
|
||||
"namedChunks": true
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"configurations": {
|
||||
"production": {
|
||||
"buildTarget": "Modernize:build:production"
|
||||
},
|
||||
"hmr": {
|
||||
"hmr": true
|
||||
},
|
||||
"development": {
|
||||
"buildTarget": "Modernize:build:development"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"buildTarget": "Modernize:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"polyfills": ["zone.js", "zone.js/testing"],
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": ["src/favicon.ico", "src/assets"],
|
||||
"styles": ["src/styles.scss"],
|
||||
"scripts": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cli": {
|
||||
"analytics": false
|
||||
}
|
||||
}
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"Modernize": {
|
||||
"projectType": "application",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"style": "scss"
|
||||
}
|
||||
},
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"allowedCommonJsDependencies": ["apexcharts", "bezier-easing", "moment"],
|
||||
"outputPath": "dist/Modernize",
|
||||
"index": "src/index.html",
|
||||
"main": "src/main.ts",
|
||||
"polyfills": ["zone.js"],
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": ["src/favicon.ico", "src/assets"],
|
||||
"styles": ["src/styles.scss", "src/assets/scss/style.scss"],
|
||||
"scripts": []
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "12mb",
|
||||
"maximumError": "12mb"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "12mb",
|
||||
"maximumError": "12mb"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"buildOptimizer": false,
|
||||
"optimization": false,
|
||||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true,
|
||||
"namedChunks": true
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"configurations": {
|
||||
"production": {
|
||||
"buildTarget": "Modernize:build:production"
|
||||
},
|
||||
"hmr": {
|
||||
"hmr": true
|
||||
},
|
||||
"development": {
|
||||
"buildTarget": "Modernize:build:development"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"buildTarget": "Modernize:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"polyfills": ["zone.js", "zone.js/testing"],
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": ["src/favicon.ico", "src/assets"],
|
||||
"styles": ["src/styles.scss"],
|
||||
"scripts": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"cli": {
|
||||
"analytics": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[[redirects]]
|
||||
from = "/*"
|
||||
to = "/index.html"
|
||||
[[redirects]]
|
||||
from = "/*"
|
||||
to = "/index.html"
|
||||
status = 200
|
||||
27602
Web/themes/modernize/package-lock.json
generated
27602
Web/themes/modernize/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,48 +1,48 @@
|
||||
{
|
||||
"name": "modernize",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"watch": "ng build --watch --configuration development",
|
||||
"test": "ng test"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^19.0.0",
|
||||
"@angular/cdk": "^19.0.0",
|
||||
"@angular/common": "^19.0.0",
|
||||
"@angular/compiler": "^19.0.0",
|
||||
"@angular/core": "^19.0.0",
|
||||
"@angular/forms": "^19.0.0",
|
||||
"@angular/material": "^19.0.0",
|
||||
"@angular/platform-browser": "^19.0.0",
|
||||
"@angular/platform-browser-dynamic": "^19.0.0",
|
||||
"@angular/router": "^19.0.0",
|
||||
"@ngx-translate/core": "^14.0.0",
|
||||
"@ngx-translate/http-loader": "^7.0.0",
|
||||
"angular-tabler-icons": "^2.7.0",
|
||||
"apexcharts": "^3.49.0",
|
||||
"ng-apexcharts": "1.7.6",
|
||||
"ngx-scrollbar": "^11.0.0",
|
||||
"rxjs": "~7.5.0",
|
||||
"sass": "1.81.0",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.15.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^19.0.1",
|
||||
"@angular/cli": "~19.0.1",
|
||||
"@angular/compiler-cli": "^19.0.0",
|
||||
"@types/date-fns": "^2.6.0",
|
||||
"@types/jasmine": "~4.3.0",
|
||||
"jasmine-core": "~4.5.0",
|
||||
"karma": "~6.4.0",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage": "~2.2.0",
|
||||
"karma-jasmine": "~5.1.0",
|
||||
"karma-jasmine-html-reporter": "~2.0.0",
|
||||
"typescript": "~5.6.3"
|
||||
}
|
||||
}
|
||||
{
|
||||
"name": "modernize",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"watch": "ng build --watch --configuration development",
|
||||
"test": "ng test"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^19.0.0",
|
||||
"@angular/cdk": "^19.0.0",
|
||||
"@angular/common": "^19.0.0",
|
||||
"@angular/compiler": "^19.0.0",
|
||||
"@angular/core": "^19.0.0",
|
||||
"@angular/forms": "^19.0.0",
|
||||
"@angular/material": "^19.0.0",
|
||||
"@angular/platform-browser": "^19.0.0",
|
||||
"@angular/platform-browser-dynamic": "^19.0.0",
|
||||
"@angular/router": "^19.0.0",
|
||||
"@ngx-translate/core": "^14.0.0",
|
||||
"@ngx-translate/http-loader": "^7.0.0",
|
||||
"angular-tabler-icons": "^2.7.0",
|
||||
"apexcharts": "^3.49.0",
|
||||
"ng-apexcharts": "1.7.6",
|
||||
"ngx-scrollbar": "^11.0.0",
|
||||
"rxjs": "~7.5.0",
|
||||
"sass": "1.81.0",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.15.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^19.0.1",
|
||||
"@angular/cli": "~19.0.1",
|
||||
"@angular/compiler-cli": "^19.0.0",
|
||||
"@types/date-fns": "^2.6.0",
|
||||
"@types/jasmine": "~4.3.0",
|
||||
"jasmine-core": "~4.5.0",
|
||||
"karma": "~6.4.0",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage": "~2.2.0",
|
||||
"karma-jasmine": "~5.1.0",
|
||||
"karma-jasmine-html-reporter": "~2.0.0",
|
||||
"typescript": "~5.6.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
<router-outlet></router-outlet>
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
describe('AppComponent', () => {
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [
|
||||
RouterTestingModule
|
||||
],
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
it('should create the app', () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should have as title 'Angular15'`, () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.componentInstance;
|
||||
expect(app.title).toEqual('Angular15');
|
||||
});
|
||||
|
||||
it('should render title', () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
fixture.detectChanges();
|
||||
const compiled = fixture.nativeElement as HTMLElement;
|
||||
expect(compiled.querySelector('.content span')?.textContent).toContain('Angular15 app is running!');
|
||||
});
|
||||
});
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
describe('AppComponent', () => {
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [
|
||||
RouterTestingModule
|
||||
],
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
it('should create the app', () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should have as title 'Angular15'`, () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.componentInstance;
|
||||
expect(app.title).toEqual('Angular15');
|
||||
});
|
||||
|
||||
it('should render title', () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
fixture.detectChanges();
|
||||
const compiled = fixture.nativeElement as HTMLElement;
|
||||
expect(compiled.querySelector('.content span')?.textContent).toContain('Angular15 app is running!');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { RouterOutlet } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
imports: [RouterOutlet],
|
||||
templateUrl: './app.component.html'
|
||||
})
|
||||
export class AppComponent {
|
||||
title = 'Modernize Angular Admin Template';
|
||||
}
|
||||
import { Component } from '@angular/core';
|
||||
import { RouterOutlet } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
imports: [RouterOutlet],
|
||||
templateUrl: './app.component.html'
|
||||
})
|
||||
export class AppComponent {
|
||||
title = 'Modernize Angular Admin Template';
|
||||
}
|
||||
|
||||
@@ -1,55 +1,55 @@
|
||||
import {
|
||||
ApplicationConfig,
|
||||
provideZoneChangeDetection,
|
||||
importProvidersFrom,
|
||||
} from '@angular/core';
|
||||
import {
|
||||
HttpClient,
|
||||
provideHttpClient,
|
||||
withInterceptorsFromDi,
|
||||
} from '@angular/common/http';
|
||||
import { routes } from './app.routes';
|
||||
import {
|
||||
provideRouter,
|
||||
withComponentInputBinding,
|
||||
withInMemoryScrolling,
|
||||
} from '@angular/router';
|
||||
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
|
||||
import { provideClientHydration } from '@angular/platform-browser';
|
||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
||||
|
||||
// icons
|
||||
import { TablerIconsModule } from 'angular-tabler-icons';
|
||||
import * as TablerIcons from 'angular-tabler-icons/icons';
|
||||
|
||||
// perfect scrollbar
|
||||
import { NgScrollbarModule } from 'ngx-scrollbar';
|
||||
|
||||
//Import all material modules
|
||||
import { MaterialModule } from './material.module';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
provideZoneChangeDetection({ eventCoalescing: true }),
|
||||
provideRouter(
|
||||
routes,
|
||||
withInMemoryScrolling({
|
||||
scrollPositionRestoration: 'enabled',
|
||||
anchorScrolling: 'enabled',
|
||||
}),
|
||||
withComponentInputBinding()
|
||||
),
|
||||
provideHttpClient(withInterceptorsFromDi()),
|
||||
provideClientHydration(),
|
||||
provideAnimationsAsync(),
|
||||
importProvidersFrom(
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
MaterialModule,
|
||||
TablerIconsModule.pick(TablerIcons),
|
||||
NgScrollbarModule,
|
||||
),
|
||||
],
|
||||
};
|
||||
import {
|
||||
ApplicationConfig,
|
||||
provideZoneChangeDetection,
|
||||
importProvidersFrom,
|
||||
} from '@angular/core';
|
||||
import {
|
||||
HttpClient,
|
||||
provideHttpClient,
|
||||
withInterceptorsFromDi,
|
||||
} from '@angular/common/http';
|
||||
import { routes } from './app.routes';
|
||||
import {
|
||||
provideRouter,
|
||||
withComponentInputBinding,
|
||||
withInMemoryScrolling,
|
||||
} from '@angular/router';
|
||||
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
|
||||
import { provideClientHydration } from '@angular/platform-browser';
|
||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
||||
|
||||
// icons
|
||||
import { TablerIconsModule } from 'angular-tabler-icons';
|
||||
import * as TablerIcons from 'angular-tabler-icons/icons';
|
||||
|
||||
// perfect scrollbar
|
||||
import { NgScrollbarModule } from 'ngx-scrollbar';
|
||||
|
||||
//Import all material modules
|
||||
import { MaterialModule } from './material.module';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
provideZoneChangeDetection({ eventCoalescing: true }),
|
||||
provideRouter(
|
||||
routes,
|
||||
withInMemoryScrolling({
|
||||
scrollPositionRestoration: 'enabled',
|
||||
anchorScrolling: 'enabled',
|
||||
}),
|
||||
withComponentInputBinding()
|
||||
),
|
||||
provideHttpClient(withInterceptorsFromDi()),
|
||||
provideClientHydration(),
|
||||
provideAnimationsAsync(),
|
||||
importProvidersFrom(
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
MaterialModule,
|
||||
TablerIconsModule.pick(TablerIcons),
|
||||
NgScrollbarModule,
|
||||
),
|
||||
],
|
||||
};
|
||||
|
||||
@@ -1,51 +1,51 @@
|
||||
import { Routes } from '@angular/router';
|
||||
import { BlankComponent } from './layouts/blank/blank.component';
|
||||
import { FullComponent } from './layouts/full/full.component';
|
||||
|
||||
export const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: FullComponent,
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
redirectTo: '/dashboard',
|
||||
pathMatch: 'full',
|
||||
},
|
||||
{
|
||||
path: 'dashboard',
|
||||
loadChildren: () =>
|
||||
import('./pages/pages.routes').then((m) => m.PagesRoutes),
|
||||
},
|
||||
{
|
||||
path: 'ui-components',
|
||||
loadChildren: () =>
|
||||
import('./pages/ui-components/ui-components.routes').then(
|
||||
(m) => m.UiComponentsRoutes
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'extra',
|
||||
loadChildren: () =>
|
||||
import('./pages/extra/extra.routes').then((m) => m.ExtraRoutes),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
component: BlankComponent,
|
||||
children: [
|
||||
{
|
||||
path: 'authentication',
|
||||
loadChildren: () =>
|
||||
import('./pages/authentication/authentication.routes').then(
|
||||
(m) => m.AuthenticationRoutes
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '**',
|
||||
redirectTo: 'authentication/error',
|
||||
},
|
||||
];
|
||||
import { Routes } from '@angular/router';
|
||||
import { BlankComponent } from './layouts/blank/blank.component';
|
||||
import { FullComponent } from './layouts/full/full.component';
|
||||
|
||||
export const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: FullComponent,
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
redirectTo: '/dashboard',
|
||||
pathMatch: 'full',
|
||||
},
|
||||
{
|
||||
path: 'dashboard',
|
||||
loadChildren: () =>
|
||||
import('./pages/pages.routes').then((m) => m.PagesRoutes),
|
||||
},
|
||||
{
|
||||
path: 'ui-components',
|
||||
loadChildren: () =>
|
||||
import('./pages/ui-components/ui-components.routes').then(
|
||||
(m) => m.UiComponentsRoutes
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'extra',
|
||||
loadChildren: () =>
|
||||
import('./pages/extra/extra.routes').then((m) => m.ExtraRoutes),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
component: BlankComponent,
|
||||
children: [
|
||||
{
|
||||
path: 'authentication',
|
||||
loadChildren: () =>
|
||||
import('./pages/authentication/authentication.routes').then(
|
||||
(m) => m.AuthenticationRoutes
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '**',
|
||||
redirectTo: 'authentication/error',
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
<div class="row">
|
||||
@for(productcard of productcards; track productcards) {
|
||||
<div class="col-sm-6 col-lg-3">
|
||||
<mat-card class="cardWithShadow productcard overflow-hidden">
|
||||
<a routerLink="/widgets/cards">
|
||||
<img src="{{ productcard.imgSrc }}" alt="imgSrc" class="w-100" mat-card-image />
|
||||
</a>
|
||||
<mat-card-content class="p-b-24 p-t-12 position-relative">
|
||||
<button mat-mini-fab class="icon-30 cart-btn bg-primary text-white d-block" matTooltip="Add to Cart">
|
||||
<i-tabler name="basket" class="icon-16"></i-tabler>
|
||||
</button>
|
||||
<mat-card-title class="mat-headline-2 f-s-16 m-b-4">{{
|
||||
productcard.title
|
||||
}}</mat-card-title>
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<div class="d-flex align-items-center">
|
||||
<h6 class="f-w-600 f-s-16">${{ productcard.price }}</h6>
|
||||
<span class="f-s-14 m-l-4 text-decoration-line-through">${{ productcard.rprice }}</span>
|
||||
</div>
|
||||
<div class="m-l-auto d-flex gap-4">
|
||||
<span><i-tabler name="star" class="fill-warning icon-18"></i-tabler></span>
|
||||
<span><i-tabler name="star" class="fill-warning icon-18"></i-tabler></span>
|
||||
<span><i-tabler name="star" class="fill-warning icon-18"></i-tabler></span>
|
||||
<span><i-tabler name="star" class="fill-warning icon-18"></i-tabler></span>
|
||||
<span><i-tabler name="star" class="fill-warning icon-18"></i-tabler></span>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
}
|
||||
<div class="row">
|
||||
@for(productcard of productcards; track productcards) {
|
||||
<div class="col-sm-6 col-lg-3">
|
||||
<mat-card class="cardWithShadow productcard overflow-hidden">
|
||||
<a routerLink="/widgets/cards">
|
||||
<img src="{{ productcard.imgSrc }}" alt="imgSrc" class="w-100" mat-card-image />
|
||||
</a>
|
||||
<mat-card-content class="p-b-24 p-t-12 position-relative">
|
||||
<button mat-mini-fab class="icon-30 cart-btn bg-primary text-white d-block" matTooltip="Add to Cart">
|
||||
<i-tabler name="basket" class="icon-16"></i-tabler>
|
||||
</button>
|
||||
<mat-card-title class="mat-headline-2 f-s-16 m-b-4">{{
|
||||
productcard.title
|
||||
}}</mat-card-title>
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<div class="d-flex align-items-center">
|
||||
<h6 class="f-w-600 f-s-16">${{ productcard.price }}</h6>
|
||||
<span class="f-s-14 m-l-4 text-decoration-line-through">${{ productcard.rprice }}</span>
|
||||
</div>
|
||||
<div class="m-l-auto d-flex gap-4">
|
||||
<span><i-tabler name="star" class="fill-warning icon-18"></i-tabler></span>
|
||||
<span><i-tabler name="star" class="fill-warning icon-18"></i-tabler></span>
|
||||
<span><i-tabler name="star" class="fill-warning icon-18"></i-tabler></span>
|
||||
<span><i-tabler name="star" class="fill-warning icon-18"></i-tabler></span>
|
||||
<span><i-tabler name="star" class="fill-warning icon-18"></i-tabler></span>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@@ -1,53 +1,53 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { TablerIconsModule } from 'angular-tabler-icons';
|
||||
|
||||
// ecommerce card
|
||||
interface productCards {
|
||||
id: number;
|
||||
imgSrc: string;
|
||||
title: string;
|
||||
price: string;
|
||||
rprice: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-blog-card',
|
||||
imports: [MatCardModule, TablerIconsModule, MatButtonModule],
|
||||
templateUrl: './blog-card.component.html',
|
||||
})
|
||||
export class AppBlogCardsComponent {
|
||||
constructor() { }
|
||||
|
||||
productcards: productCards[] = [
|
||||
{
|
||||
id: 1,
|
||||
imgSrc: '/assets/images/products/s4.jpg',
|
||||
title: 'Boat Headphone',
|
||||
price: '285',
|
||||
rprice: '375',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
imgSrc: '/assets/images/products/s5.jpg',
|
||||
title: 'MacBook Air Pro',
|
||||
price: '285',
|
||||
rprice: '375',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
imgSrc: '/assets/images/products/s7.jpg',
|
||||
title: 'Red Valvet Dress',
|
||||
price: '285',
|
||||
rprice: '375',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
imgSrc: '/assets/images/products/s11.jpg',
|
||||
title: 'Cute Soft Teddybear',
|
||||
price: '285',
|
||||
rprice: '375',
|
||||
},
|
||||
];
|
||||
}
|
||||
import { Component } from '@angular/core';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { TablerIconsModule } from 'angular-tabler-icons';
|
||||
|
||||
// ecommerce card
|
||||
interface productCards {
|
||||
id: number;
|
||||
imgSrc: string;
|
||||
title: string;
|
||||
price: string;
|
||||
rprice: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-blog-card',
|
||||
imports: [MatCardModule, TablerIconsModule, MatButtonModule],
|
||||
templateUrl: './blog-card.component.html',
|
||||
})
|
||||
export class AppBlogCardsComponent {
|
||||
constructor() { }
|
||||
|
||||
productcards: productCards[] = [
|
||||
{
|
||||
id: 1,
|
||||
imgSrc: '/assets/images/products/s4.jpg',
|
||||
title: 'Boat Headphone',
|
||||
price: '285',
|
||||
rprice: '375',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
imgSrc: '/assets/images/products/s5.jpg',
|
||||
title: 'MacBook Air Pro',
|
||||
price: '285',
|
||||
rprice: '375',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
imgSrc: '/assets/images/products/s7.jpg',
|
||||
title: 'Red Valvet Dress',
|
||||
price: '285',
|
||||
rprice: '375',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
imgSrc: '/assets/images/products/s11.jpg',
|
||||
title: 'Cute Soft Teddybear',
|
||||
price: '285',
|
||||
rprice: '375',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
<mat-card class="cardWithShadow overflow-hidden">
|
||||
<mat-card-content class="p-b-0">
|
||||
<div class="d-flex align-items-center m-b-8">
|
||||
<mat-card-title>Monthly Earnings</mat-card-title>
|
||||
<div class="m-l-auto">
|
||||
<button mat-fab class="icon-48 bg-secondary ">
|
||||
<i-tabler name="currency-dollar" class="text-white d-flex"></i-tabler>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<h4 class="f-s-24 m-b-6">$6,820</h4>
|
||||
<div class="d-flex align-items-center m-t-16">
|
||||
<button mat-mini-fab class="bg-light-error text-error shadow-none icon-27 p-0 d-flex align-items-center justify-content-center">
|
||||
<i-tabler name="arrow-down-right" class="icon-20 d-flex align-items-center"></i-tabler>
|
||||
</button>
|
||||
<div class="f-s-14 f-w-600 m-l-12">+9%</div>
|
||||
<div class="f-s-14 m-l-4">last year</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
<apx-chart [series]="monthlyChart.series" [dataLabels]="monthlyChart.dataLabels" [chart]="monthlyChart.chart"
|
||||
[legend]="monthlyChart.legend" [colors]="monthlyChart.colors" [stroke]="monthlyChart.stroke"
|
||||
[tooltip]="monthlyChart.tooltip" [plotOptions]="monthlyChart.plotOptions"
|
||||
[responsive]="monthlyChart.responsive"></apx-chart>
|
||||
<mat-card class="cardWithShadow overflow-hidden">
|
||||
<mat-card-content class="p-b-0">
|
||||
<div class="d-flex align-items-center m-b-8">
|
||||
<mat-card-title>Monthly Earnings</mat-card-title>
|
||||
<div class="m-l-auto">
|
||||
<button mat-fab class="icon-48 bg-secondary ">
|
||||
<i-tabler name="currency-dollar" class="text-white d-flex"></i-tabler>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<h4 class="f-s-24 m-b-6">$6,820</h4>
|
||||
<div class="d-flex align-items-center m-t-16">
|
||||
<button mat-mini-fab class="bg-light-error text-error shadow-none icon-27 p-0 d-flex align-items-center justify-content-center">
|
||||
<i-tabler name="arrow-down-right" class="icon-20 d-flex align-items-center"></i-tabler>
|
||||
</button>
|
||||
<div class="f-s-14 f-w-600 m-l-12">+9%</div>
|
||||
<div class="f-s-14 m-l-4">last year</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
<apx-chart [series]="monthlyChart.series" [dataLabels]="monthlyChart.dataLabels" [chart]="monthlyChart.chart"
|
||||
[legend]="monthlyChart.legend" [colors]="monthlyChart.colors" [stroke]="monthlyChart.stroke"
|
||||
[tooltip]="monthlyChart.tooltip" [plotOptions]="monthlyChart.plotOptions"
|
||||
[responsive]="monthlyChart.responsive"></apx-chart>
|
||||
</mat-card>
|
||||
@@ -1,81 +1,81 @@
|
||||
import { Component, ViewChild } from '@angular/core';
|
||||
import {
|
||||
ApexChart,
|
||||
ChartComponent,
|
||||
ApexDataLabels,
|
||||
ApexLegend,
|
||||
ApexStroke,
|
||||
ApexTooltip,
|
||||
ApexAxisChartSeries,
|
||||
ApexPlotOptions,
|
||||
ApexResponsive,
|
||||
NgApexchartsModule,
|
||||
} from 'ng-apexcharts';
|
||||
|
||||
import { TablerIconsModule } from 'angular-tabler-icons';
|
||||
import { MaterialModule } from 'src/app/material.module';
|
||||
|
||||
export interface monthlyChart {
|
||||
series: ApexAxisChartSeries;
|
||||
chart: ApexChart;
|
||||
dataLabels: ApexDataLabels;
|
||||
plotOptions: ApexPlotOptions;
|
||||
tooltip: ApexTooltip;
|
||||
stroke: ApexStroke;
|
||||
legend: ApexLegend;
|
||||
responsive: ApexResponsive;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-monthly-earnings',
|
||||
imports: [NgApexchartsModule, MaterialModule, TablerIconsModule],
|
||||
templateUrl: './monthly-earnings.component.html',
|
||||
})
|
||||
export class AppMonthlyEarningsComponent {
|
||||
@ViewChild('chart') chart: ChartComponent = Object.create(null);
|
||||
public monthlyChart!: Partial<monthlyChart> | any;
|
||||
|
||||
constructor() {
|
||||
this.monthlyChart = {
|
||||
series: [
|
||||
{
|
||||
name: '',
|
||||
color: '#49BEFF',
|
||||
data: [25, 66, 20, 40, 12, 58, 20],
|
||||
},
|
||||
],
|
||||
|
||||
chart: {
|
||||
type: 'area',
|
||||
fontFamily: "'Plus Jakarta Sans', sans-serif;",
|
||||
foreColor: '#adb0bb',
|
||||
toolbar: {
|
||||
show: false,
|
||||
},
|
||||
height: 85,
|
||||
sparkline: {
|
||||
enabled: true,
|
||||
},
|
||||
group: 'sparklines',
|
||||
},
|
||||
stroke: {
|
||||
curve: 'smooth',
|
||||
width: 2,
|
||||
},
|
||||
fill: {
|
||||
colors: ['#E8F7FF'],
|
||||
type: 'solid',
|
||||
opacity: 0.05,
|
||||
},
|
||||
markers: {
|
||||
size: 0,
|
||||
},
|
||||
tooltip: {
|
||||
theme: 'dark',
|
||||
x: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
import { Component, ViewChild } from '@angular/core';
|
||||
import {
|
||||
ApexChart,
|
||||
ChartComponent,
|
||||
ApexDataLabels,
|
||||
ApexLegend,
|
||||
ApexStroke,
|
||||
ApexTooltip,
|
||||
ApexAxisChartSeries,
|
||||
ApexPlotOptions,
|
||||
ApexResponsive,
|
||||
NgApexchartsModule,
|
||||
} from 'ng-apexcharts';
|
||||
|
||||
import { TablerIconsModule } from 'angular-tabler-icons';
|
||||
import { MaterialModule } from 'src/app/material.module';
|
||||
|
||||
export interface monthlyChart {
|
||||
series: ApexAxisChartSeries;
|
||||
chart: ApexChart;
|
||||
dataLabels: ApexDataLabels;
|
||||
plotOptions: ApexPlotOptions;
|
||||
tooltip: ApexTooltip;
|
||||
stroke: ApexStroke;
|
||||
legend: ApexLegend;
|
||||
responsive: ApexResponsive;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-monthly-earnings',
|
||||
imports: [NgApexchartsModule, MaterialModule, TablerIconsModule],
|
||||
templateUrl: './monthly-earnings.component.html',
|
||||
})
|
||||
export class AppMonthlyEarningsComponent {
|
||||
@ViewChild('chart') chart: ChartComponent = Object.create(null);
|
||||
public monthlyChart!: Partial<monthlyChart> | any;
|
||||
|
||||
constructor() {
|
||||
this.monthlyChart = {
|
||||
series: [
|
||||
{
|
||||
name: '',
|
||||
color: '#49BEFF',
|
||||
data: [25, 66, 20, 40, 12, 58, 20],
|
||||
},
|
||||
],
|
||||
|
||||
chart: {
|
||||
type: 'area',
|
||||
fontFamily: "'Plus Jakarta Sans', sans-serif;",
|
||||
foreColor: '#adb0bb',
|
||||
toolbar: {
|
||||
show: false,
|
||||
},
|
||||
height: 85,
|
||||
sparkline: {
|
||||
enabled: true,
|
||||
},
|
||||
group: 'sparklines',
|
||||
},
|
||||
stroke: {
|
||||
curve: 'smooth',
|
||||
width: 2,
|
||||
},
|
||||
fill: {
|
||||
colors: ['#E8F7FF'],
|
||||
type: 'solid',
|
||||
opacity: 0.05,
|
||||
},
|
||||
markers: {
|
||||
size: 0,
|
||||
},
|
||||
tooltip: {
|
||||
theme: 'dark',
|
||||
x: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,98 +1,98 @@
|
||||
<mat-card class="cardWithShadow">
|
||||
<mat-card-content>
|
||||
<div class="d-flex">
|
||||
<div class="m-r-auto">
|
||||
<mat-card-title>Top Projects</mat-card-title>
|
||||
<mat-card-subtitle>Best Products</mat-card-subtitle>
|
||||
</div>
|
||||
<mat-form-field class="theme-select" appearance="outline">
|
||||
<mat-select value="mar">
|
||||
@for(month of months; track month.value) {
|
||||
<mat-option [value]="month.value">
|
||||
{{ month.viewValue }}
|
||||
</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table mat-table [dataSource]="dataSource" class="w-100">
|
||||
<!-- Position Column -->
|
||||
<ng-container matColumnDef="product">
|
||||
<th mat-header-cell *matHeaderCellDef class="f-w-600 f-s-14 p-l-0">
|
||||
Product
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let element" class="p-l-0">
|
||||
<div class="d-flex align-items-center">
|
||||
<img [src]="element.imagePath" alt="users" width="48" class="rounded" />
|
||||
<div class="m-l-16">
|
||||
<h6 class="f-s-14 f-w-600">
|
||||
{{ element.pname }}
|
||||
</h6>
|
||||
<span class=" f-s-12">
|
||||
{{ element.category }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Name Column -->
|
||||
<ng-container matColumnDef="progress">
|
||||
<th mat-header-cell *matHeaderCellDef class="f-w-600 f-s-14">
|
||||
Progress
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let element">
|
||||
{{ element.progress }}%
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Weight Column -->
|
||||
<ng-container matColumnDef="status">
|
||||
<th mat-header-cell *matHeaderCellDef class="f-w-600 f-s-14">
|
||||
Status
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let element">
|
||||
@if(element.status == 'low') {
|
||||
<span class="bg-light-success text-success rounded f-w-600 p-6 p-y-4 f-s-12">
|
||||
{{ element.status | titlecase }}
|
||||
</span>
|
||||
}
|
||||
|
||||
@if(element.status == 'medium') {
|
||||
<span class="bg-light-warning text-warning rounded f-w-600 p-6 p-y-4 f-s-12">
|
||||
{{ element.status | titlecase }}
|
||||
</span>
|
||||
}
|
||||
|
||||
@if(element.status == 'high') {
|
||||
<span class="bg-light-primary text-primary rounded f-w-600 p-6 p-y-4 f-s-12">
|
||||
{{ element.status | titlecase }}
|
||||
</span>
|
||||
}
|
||||
|
||||
@if(element.status == 'critical') {
|
||||
<span class="bg-light-error text-error rounded f-w-600 p-6 p-y-4 f-s-12">
|
||||
{{ element.status | titlecase }}
|
||||
</span>
|
||||
}
|
||||
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Symbol Column -->
|
||||
<ng-container matColumnDef="sales">
|
||||
<th mat-header-cell *matHeaderCellDef class="f-w-600 f-s-14">
|
||||
Sales
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let element">
|
||||
${{ element.sales }}k
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
|
||||
</table>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
<mat-card class="cardWithShadow">
|
||||
<mat-card-content>
|
||||
<div class="d-flex">
|
||||
<div class="m-r-auto">
|
||||
<mat-card-title>Top Projects</mat-card-title>
|
||||
<mat-card-subtitle>Best Products</mat-card-subtitle>
|
||||
</div>
|
||||
<mat-form-field class="theme-select" appearance="outline">
|
||||
<mat-select value="mar">
|
||||
@for(month of months; track month.value) {
|
||||
<mat-option [value]="month.value">
|
||||
{{ month.viewValue }}
|
||||
</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table mat-table [dataSource]="dataSource" class="w-100">
|
||||
<!-- Position Column -->
|
||||
<ng-container matColumnDef="product">
|
||||
<th mat-header-cell *matHeaderCellDef class="f-w-600 f-s-14 p-l-0">
|
||||
Product
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let element" class="p-l-0">
|
||||
<div class="d-flex align-items-center">
|
||||
<img [src]="element.imagePath" alt="users" width="48" class="rounded" />
|
||||
<div class="m-l-16">
|
||||
<h6 class="f-s-14 f-w-600">
|
||||
{{ element.pname }}
|
||||
</h6>
|
||||
<span class=" f-s-12">
|
||||
{{ element.category }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Name Column -->
|
||||
<ng-container matColumnDef="progress">
|
||||
<th mat-header-cell *matHeaderCellDef class="f-w-600 f-s-14">
|
||||
Progress
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let element">
|
||||
{{ element.progress }}%
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Weight Column -->
|
||||
<ng-container matColumnDef="status">
|
||||
<th mat-header-cell *matHeaderCellDef class="f-w-600 f-s-14">
|
||||
Status
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let element">
|
||||
@if(element.status == 'low') {
|
||||
<span class="bg-light-success text-success rounded f-w-600 p-6 p-y-4 f-s-12">
|
||||
{{ element.status | titlecase }}
|
||||
</span>
|
||||
}
|
||||
|
||||
@if(element.status == 'medium') {
|
||||
<span class="bg-light-warning text-warning rounded f-w-600 p-6 p-y-4 f-s-12">
|
||||
{{ element.status | titlecase }}
|
||||
</span>
|
||||
}
|
||||
|
||||
@if(element.status == 'high') {
|
||||
<span class="bg-light-primary text-primary rounded f-w-600 p-6 p-y-4 f-s-12">
|
||||
{{ element.status | titlecase }}
|
||||
</span>
|
||||
}
|
||||
|
||||
@if(element.status == 'critical') {
|
||||
<span class="bg-light-error text-error rounded f-w-600 p-6 p-y-4 f-s-12">
|
||||
{{ element.status | titlecase }}
|
||||
</span>
|
||||
}
|
||||
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Symbol Column -->
|
||||
<ng-container matColumnDef="sales">
|
||||
<th mat-header-cell *matHeaderCellDef class="f-w-600 f-s-14">
|
||||
Sales
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let element">
|
||||
${{ element.sales }}k
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
|
||||
</table>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
@@ -1,80 +1,80 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { NgApexchartsModule } from 'ng-apexcharts';
|
||||
import { TablerIconsModule } from 'angular-tabler-icons';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { MaterialModule } from 'src/app/material.module';
|
||||
|
||||
export interface performanceData {
|
||||
id: number;
|
||||
imagePath: string;
|
||||
pname: string;
|
||||
category: string;
|
||||
progress: number;
|
||||
sales: number;
|
||||
status: string;
|
||||
}
|
||||
|
||||
const ELEMENT_DATA: performanceData[] = [
|
||||
{
|
||||
id: 1,
|
||||
imagePath: 'assets/images/products/s6.jpg',
|
||||
pname: 'Gaming Console',
|
||||
category: 'Electronics',
|
||||
progress: 78.5,
|
||||
sales: 3.9,
|
||||
status: 'low',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
imagePath: 'assets/images/products/s9.jpg',
|
||||
pname: 'Leather Purse',
|
||||
category: 'Fashion',
|
||||
progress: 58.6,
|
||||
sales: 3.5,
|
||||
status: 'medium',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
imagePath: 'assets/images/products/s7.jpg',
|
||||
pname: 'Red Velvate Dress',
|
||||
category: 'Womens Fashion',
|
||||
progress: 25,
|
||||
sales: 3.8,
|
||||
status: 'high',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
imagePath: 'assets/images/products/s4.jpg',
|
||||
pname: 'Headphone Boat',
|
||||
category: 'Electronics',
|
||||
progress: 96.3,
|
||||
sales: 3.54,
|
||||
status: 'critical',
|
||||
},
|
||||
];
|
||||
|
||||
interface month {
|
||||
value: string;
|
||||
viewValue: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-product-performance',
|
||||
imports: [
|
||||
NgApexchartsModule,
|
||||
MaterialModule,
|
||||
TablerIconsModule,
|
||||
CommonModule,
|
||||
],
|
||||
templateUrl: './product-performance.component.html',
|
||||
})
|
||||
export class AppProductPerformanceComponent {
|
||||
displayedColumns: string[] = ['product', 'progress', 'status', 'sales'];
|
||||
dataSource = ELEMENT_DATA;
|
||||
|
||||
months: month[] = [
|
||||
{ value: 'mar', viewValue: 'March 2025' },
|
||||
{ value: 'apr', viewValue: 'April 2025' },
|
||||
{ value: 'june', viewValue: 'June 2025' },
|
||||
];
|
||||
}
|
||||
import { Component } from '@angular/core';
|
||||
import { NgApexchartsModule } from 'ng-apexcharts';
|
||||
import { TablerIconsModule } from 'angular-tabler-icons';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { MaterialModule } from 'src/app/material.module';
|
||||
|
||||
export interface performanceData {
|
||||
id: number;
|
||||
imagePath: string;
|
||||
pname: string;
|
||||
category: string;
|
||||
progress: number;
|
||||
sales: number;
|
||||
status: string;
|
||||
}
|
||||
|
||||
const ELEMENT_DATA: performanceData[] = [
|
||||
{
|
||||
id: 1,
|
||||
imagePath: 'assets/images/products/s6.jpg',
|
||||
pname: 'Gaming Console',
|
||||
category: 'Electronics',
|
||||
progress: 78.5,
|
||||
sales: 3.9,
|
||||
status: 'low',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
imagePath: 'assets/images/products/s9.jpg',
|
||||
pname: 'Leather Purse',
|
||||
category: 'Fashion',
|
||||
progress: 58.6,
|
||||
sales: 3.5,
|
||||
status: 'medium',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
imagePath: 'assets/images/products/s7.jpg',
|
||||
pname: 'Red Velvate Dress',
|
||||
category: 'Womens Fashion',
|
||||
progress: 25,
|
||||
sales: 3.8,
|
||||
status: 'high',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
imagePath: 'assets/images/products/s4.jpg',
|
||||
pname: 'Headphone Boat',
|
||||
category: 'Electronics',
|
||||
progress: 96.3,
|
||||
sales: 3.54,
|
||||
status: 'critical',
|
||||
},
|
||||
];
|
||||
|
||||
interface month {
|
||||
value: string;
|
||||
viewValue: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-product-performance',
|
||||
imports: [
|
||||
NgApexchartsModule,
|
||||
MaterialModule,
|
||||
TablerIconsModule,
|
||||
CommonModule,
|
||||
],
|
||||
templateUrl: './product-performance.component.html',
|
||||
})
|
||||
export class AppProductPerformanceComponent {
|
||||
displayedColumns: string[] = ['product', 'progress', 'status', 'sales'];
|
||||
dataSource = ELEMENT_DATA;
|
||||
|
||||
months: month[] = [
|
||||
{ value: 'mar', viewValue: 'March 2025' },
|
||||
{ value: 'apr', viewValue: 'April 2025' },
|
||||
{ value: 'june', viewValue: 'June 2025' },
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
<mat-card class="cardWithShadow">
|
||||
<mat-card-content>
|
||||
<mat-card-title>Recent Transactions</mat-card-title>
|
||||
|
||||
<div class="timeline m-t-24">
|
||||
@for(stat of stats; track stat.title) {
|
||||
<div class="timeline-item d-flex overflow-hidden">
|
||||
<div class="time text-right f-s-14">{{ stat.time }}</div>
|
||||
<div class="point d-flex align-items-center">
|
||||
<span class="timeline-badge border-{{ stat.color }} m-y-8"></span>
|
||||
<span class="timline-border d-block"></span>
|
||||
</div>
|
||||
<div class="desc">
|
||||
@if(stat.subtext) {
|
||||
<span class="f-s-14 lh-20">{{ stat.subtext }}</span>
|
||||
}
|
||||
|
||||
@if(stat.title) {
|
||||
<span class="f-s-14 lh-20 f-w-600 d-block">{{
|
||||
stat.title
|
||||
}}</span>
|
||||
}
|
||||
|
||||
@if(stat.link) {
|
||||
<a href="#" class="text-primary text-decoration-none f-s-14">#ML-3467</a>
|
||||
}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</mat-card-content>
|
||||
<mat-card class="cardWithShadow">
|
||||
<mat-card-content>
|
||||
<mat-card-title>Recent Transactions</mat-card-title>
|
||||
|
||||
<div class="timeline m-t-24">
|
||||
@for(stat of stats; track stat.title) {
|
||||
<div class="timeline-item d-flex overflow-hidden">
|
||||
<div class="time text-right f-s-14">{{ stat.time }}</div>
|
||||
<div class="point d-flex align-items-center">
|
||||
<span class="timeline-badge border-{{ stat.color }} m-y-8"></span>
|
||||
<span class="timline-border d-block"></span>
|
||||
</div>
|
||||
<div class="desc">
|
||||
@if(stat.subtext) {
|
||||
<span class="f-s-14 lh-20">{{ stat.subtext }}</span>
|
||||
}
|
||||
|
||||
@if(stat.title) {
|
||||
<span class="f-s-14 lh-20 f-w-600 d-block">{{
|
||||
stat.title
|
||||
}}</span>
|
||||
}
|
||||
|
||||
@if(stat.link) {
|
||||
<a href="#" class="text-primary text-decoration-none f-s-14">#ML-3467</a>
|
||||
}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
@@ -1,62 +1,62 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { NgApexchartsModule } from 'ng-apexcharts';
|
||||
import { MaterialModule } from 'src/app/material.module';
|
||||
|
||||
|
||||
interface stats {
|
||||
id: number;
|
||||
time: string;
|
||||
color: string;
|
||||
title?: string;
|
||||
subtext?: string;
|
||||
link?: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-recent-transactions',
|
||||
imports: [NgApexchartsModule, MaterialModule],
|
||||
templateUrl: './recent-transactions.component.html',
|
||||
})
|
||||
export class AppRecentTransactionsComponent {
|
||||
stats: stats[] = [
|
||||
{
|
||||
id: 1,
|
||||
time: '09.30 am',
|
||||
color: 'primary',
|
||||
subtext: 'Payment received from John Doe of $385.90',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
time: '10.30 am',
|
||||
color: 'accent',
|
||||
title: 'New sale recorded',
|
||||
link: '#ML-3467',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
time: '12.30 pm',
|
||||
color: 'success',
|
||||
subtext: 'Payment was made of $64.95 to Michael',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
time: '12.30 pm',
|
||||
color: 'warning',
|
||||
title: 'New sale recorded',
|
||||
link: '#ML-3467',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
time: '12.30 pm',
|
||||
color: 'error',
|
||||
title: 'New arrival recorded',
|
||||
link: '#ML-3467',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
time: '12.30 pm',
|
||||
color: 'success',
|
||||
subtext: 'Payment Done',
|
||||
},
|
||||
];
|
||||
}
|
||||
import { Component } from '@angular/core';
|
||||
import { NgApexchartsModule } from 'ng-apexcharts';
|
||||
import { MaterialModule } from 'src/app/material.module';
|
||||
|
||||
|
||||
interface stats {
|
||||
id: number;
|
||||
time: string;
|
||||
color: string;
|
||||
title?: string;
|
||||
subtext?: string;
|
||||
link?: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-recent-transactions',
|
||||
imports: [NgApexchartsModule, MaterialModule],
|
||||
templateUrl: './recent-transactions.component.html',
|
||||
})
|
||||
export class AppRecentTransactionsComponent {
|
||||
stats: stats[] = [
|
||||
{
|
||||
id: 1,
|
||||
time: '09.30 am',
|
||||
color: 'primary',
|
||||
subtext: 'Payment received from John Doe of $385.90',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
time: '10.30 am',
|
||||
color: 'accent',
|
||||
title: 'New sale recorded',
|
||||
link: '#ML-3467',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
time: '12.30 pm',
|
||||
color: 'success',
|
||||
subtext: 'Payment was made of $64.95 to Michael',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
time: '12.30 pm',
|
||||
color: 'warning',
|
||||
title: 'New sale recorded',
|
||||
link: '#ML-3467',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
time: '12.30 pm',
|
||||
color: 'error',
|
||||
title: 'New arrival recorded',
|
||||
link: '#ML-3467',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
time: '12.30 pm',
|
||||
color: 'success',
|
||||
subtext: 'Payment Done',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
<mat-card class="cardWithShadow">
|
||||
<mat-card-content>
|
||||
<div class="d-flex w-100">
|
||||
<mat-card-title>Sales Overview</mat-card-title>
|
||||
<div class="m-l-auto">
|
||||
<mat-form-field class="theme-select" appearance="outline">
|
||||
<mat-select value="mar">
|
||||
@for(month of months; track month.viewValue ) {
|
||||
<mat-option [value]="month.value">
|
||||
{{ month.viewValue }}
|
||||
</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<apx-chart [series]="salesOverviewChart.series" [dataLabels]="salesOverviewChart.dataLabels"
|
||||
[chart]="salesOverviewChart.chart" [legend]="salesOverviewChart.legend" [xaxis]="salesOverviewChart.xaxis"
|
||||
[yaxis]="salesOverviewChart.yaxis" [grid]="salesOverviewChart.grid" [stroke]="salesOverviewChart.stroke"
|
||||
[tooltip]="salesOverviewChart.tooltip" [plotOptions]="salesOverviewChart.plotOptions"></apx-chart>
|
||||
</mat-card-content>
|
||||
<mat-card class="cardWithShadow">
|
||||
<mat-card-content>
|
||||
<div class="d-flex w-100">
|
||||
<mat-card-title>Sales Overview</mat-card-title>
|
||||
<div class="m-l-auto">
|
||||
<mat-form-field class="theme-select" appearance="outline">
|
||||
<mat-select value="mar">
|
||||
@for(month of months; track month.viewValue ) {
|
||||
<mat-option [value]="month.value">
|
||||
{{ month.viewValue }}
|
||||
</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<apx-chart [series]="salesOverviewChart.series" [dataLabels]="salesOverviewChart.dataLabels"
|
||||
[chart]="salesOverviewChart.chart" [legend]="salesOverviewChart.legend" [xaxis]="salesOverviewChart.xaxis"
|
||||
[yaxis]="salesOverviewChart.yaxis" [grid]="salesOverviewChart.grid" [stroke]="salesOverviewChart.stroke"
|
||||
[tooltip]="salesOverviewChart.tooltip" [plotOptions]="salesOverviewChart.plotOptions"></apx-chart>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
@@ -1,153 +1,153 @@
|
||||
import { Component, ViewChild } from '@angular/core';
|
||||
import { TablerIconsModule } from 'angular-tabler-icons';
|
||||
import { MaterialModule } from 'src/app/material.module';
|
||||
|
||||
import {
|
||||
ApexChart,
|
||||
ChartComponent,
|
||||
ApexDataLabels,
|
||||
ApexLegend,
|
||||
ApexStroke,
|
||||
ApexTooltip,
|
||||
ApexAxisChartSeries,
|
||||
ApexXAxis,
|
||||
ApexYAxis,
|
||||
ApexGrid,
|
||||
ApexPlotOptions,
|
||||
ApexFill,
|
||||
ApexMarkers,
|
||||
ApexResponsive,
|
||||
NgApexchartsModule,
|
||||
} from 'ng-apexcharts';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
|
||||
interface month {
|
||||
value: string;
|
||||
viewValue: string;
|
||||
}
|
||||
|
||||
export interface salesOverviewChart {
|
||||
series: ApexAxisChartSeries;
|
||||
chart: ApexChart;
|
||||
dataLabels: ApexDataLabels;
|
||||
plotOptions: ApexPlotOptions;
|
||||
yaxis: ApexYAxis;
|
||||
xaxis: ApexXAxis;
|
||||
fill: ApexFill;
|
||||
tooltip: ApexTooltip;
|
||||
stroke: ApexStroke;
|
||||
legend: ApexLegend;
|
||||
grid: ApexGrid;
|
||||
marker: ApexMarkers;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-sales-overview',
|
||||
imports: [MaterialModule, TablerIconsModule, NgApexchartsModule, MatButtonModule],
|
||||
templateUrl: './sales-overview.component.html',
|
||||
})
|
||||
export class AppSalesOverviewComponent {
|
||||
|
||||
@ViewChild('chart') chart: ChartComponent = Object.create(null);
|
||||
|
||||
public salesOverviewChart!: Partial<salesOverviewChart> | any;
|
||||
|
||||
months: month[] = [
|
||||
{ value: 'mar', viewValue: 'Sep 2025' },
|
||||
{ value: 'apr', viewValue: 'Oct 2025' },
|
||||
{ value: 'june', viewValue: 'Nov 2025' },
|
||||
];
|
||||
|
||||
|
||||
constructor() {
|
||||
|
||||
// sales overview chart
|
||||
this.salesOverviewChart = {
|
||||
series: [
|
||||
{
|
||||
name: 'Eanings this month',
|
||||
data: [355, 390, 300, 350, 390, 180, 355, 390],
|
||||
color: '#5D87FF',
|
||||
},
|
||||
{
|
||||
name: 'Expense this month',
|
||||
data: [280, 250, 325, 215, 250, 310, 280, 250],
|
||||
color: '#49BEFF',
|
||||
},
|
||||
],
|
||||
|
||||
grid: {
|
||||
borderColor: 'rgba(0,0,0,0.1)',
|
||||
strokeDashArray: 3,
|
||||
xaxis: {
|
||||
lines: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
plotOptions: {
|
||||
bar: { horizontal: false, columnWidth: '35%', borderRadius: [4] },
|
||||
},
|
||||
chart: {
|
||||
type: 'bar',
|
||||
height: 390,
|
||||
offsetX: -15,
|
||||
toolbar: { show: false },
|
||||
foreColor: '#adb0bb',
|
||||
fontFamily: 'inherit',
|
||||
sparkline: { enabled: false },
|
||||
},
|
||||
dataLabels: { enabled: false },
|
||||
markers: { size: 0 },
|
||||
legend: { show: false },
|
||||
xaxis: {
|
||||
type: 'category',
|
||||
categories: [
|
||||
'16/08',
|
||||
'17/08',
|
||||
'18/08',
|
||||
'19/08',
|
||||
'20/08',
|
||||
'21/08',
|
||||
'22/08',
|
||||
'23/08',
|
||||
],
|
||||
labels: {
|
||||
style: { cssClass: 'grey--text lighten-2--text fill-color' },
|
||||
},
|
||||
},
|
||||
yaxis: {
|
||||
show: true,
|
||||
min: 0,
|
||||
max: 400,
|
||||
tickAmount: 4,
|
||||
labels: {
|
||||
style: {
|
||||
cssClass: 'grey--text lighten-2--text fill-color',
|
||||
},
|
||||
},
|
||||
},
|
||||
stroke: {
|
||||
show: true,
|
||||
width: 3,
|
||||
lineCap: 'butt',
|
||||
colors: ['transparent'],
|
||||
},
|
||||
tooltip: { theme: 'light' },
|
||||
|
||||
responsive: [
|
||||
{
|
||||
breakpoint: 600,
|
||||
options: {
|
||||
plotOptions: {
|
||||
bar: {
|
||||
borderRadius: 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
import { Component, ViewChild } from '@angular/core';
|
||||
import { TablerIconsModule } from 'angular-tabler-icons';
|
||||
import { MaterialModule } from 'src/app/material.module';
|
||||
|
||||
import {
|
||||
ApexChart,
|
||||
ChartComponent,
|
||||
ApexDataLabels,
|
||||
ApexLegend,
|
||||
ApexStroke,
|
||||
ApexTooltip,
|
||||
ApexAxisChartSeries,
|
||||
ApexXAxis,
|
||||
ApexYAxis,
|
||||
ApexGrid,
|
||||
ApexPlotOptions,
|
||||
ApexFill,
|
||||
ApexMarkers,
|
||||
ApexResponsive,
|
||||
NgApexchartsModule,
|
||||
} from 'ng-apexcharts';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
|
||||
interface month {
|
||||
value: string;
|
||||
viewValue: string;
|
||||
}
|
||||
|
||||
export interface salesOverviewChart {
|
||||
series: ApexAxisChartSeries;
|
||||
chart: ApexChart;
|
||||
dataLabels: ApexDataLabels;
|
||||
plotOptions: ApexPlotOptions;
|
||||
yaxis: ApexYAxis;
|
||||
xaxis: ApexXAxis;
|
||||
fill: ApexFill;
|
||||
tooltip: ApexTooltip;
|
||||
stroke: ApexStroke;
|
||||
legend: ApexLegend;
|
||||
grid: ApexGrid;
|
||||
marker: ApexMarkers;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-sales-overview',
|
||||
imports: [MaterialModule, TablerIconsModule, NgApexchartsModule, MatButtonModule],
|
||||
templateUrl: './sales-overview.component.html',
|
||||
})
|
||||
export class AppSalesOverviewComponent {
|
||||
|
||||
@ViewChild('chart') chart: ChartComponent = Object.create(null);
|
||||
|
||||
public salesOverviewChart!: Partial<salesOverviewChart> | any;
|
||||
|
||||
months: month[] = [
|
||||
{ value: 'mar', viewValue: 'Sep 2025' },
|
||||
{ value: 'apr', viewValue: 'Oct 2025' },
|
||||
{ value: 'june', viewValue: 'Nov 2025' },
|
||||
];
|
||||
|
||||
|
||||
constructor() {
|
||||
|
||||
// sales overview chart
|
||||
this.salesOverviewChart = {
|
||||
series: [
|
||||
{
|
||||
name: 'Eanings this month',
|
||||
data: [355, 390, 300, 350, 390, 180, 355, 390],
|
||||
color: '#5D87FF',
|
||||
},
|
||||
{
|
||||
name: 'Expense this month',
|
||||
data: [280, 250, 325, 215, 250, 310, 280, 250],
|
||||
color: '#49BEFF',
|
||||
},
|
||||
],
|
||||
|
||||
grid: {
|
||||
borderColor: 'rgba(0,0,0,0.1)',
|
||||
strokeDashArray: 3,
|
||||
xaxis: {
|
||||
lines: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
plotOptions: {
|
||||
bar: { horizontal: false, columnWidth: '35%', borderRadius: [4] },
|
||||
},
|
||||
chart: {
|
||||
type: 'bar',
|
||||
height: 390,
|
||||
offsetX: -15,
|
||||
toolbar: { show: false },
|
||||
foreColor: '#adb0bb',
|
||||
fontFamily: 'inherit',
|
||||
sparkline: { enabled: false },
|
||||
},
|
||||
dataLabels: { enabled: false },
|
||||
markers: { size: 0 },
|
||||
legend: { show: false },
|
||||
xaxis: {
|
||||
type: 'category',
|
||||
categories: [
|
||||
'16/08',
|
||||
'17/08',
|
||||
'18/08',
|
||||
'19/08',
|
||||
'20/08',
|
||||
'21/08',
|
||||
'22/08',
|
||||
'23/08',
|
||||
],
|
||||
labels: {
|
||||
style: { cssClass: 'grey--text lighten-2--text fill-color' },
|
||||
},
|
||||
},
|
||||
yaxis: {
|
||||
show: true,
|
||||
min: 0,
|
||||
max: 400,
|
||||
tickAmount: 4,
|
||||
labels: {
|
||||
style: {
|
||||
cssClass: 'grey--text lighten-2--text fill-color',
|
||||
},
|
||||
},
|
||||
},
|
||||
stroke: {
|
||||
show: true,
|
||||
width: 3,
|
||||
lineCap: 'butt',
|
||||
colors: ['transparent'],
|
||||
},
|
||||
tooltip: { theme: 'light' },
|
||||
|
||||
responsive: [
|
||||
{
|
||||
breakpoint: 600,
|
||||
options: {
|
||||
plotOptions: {
|
||||
bar: {
|
||||
borderRadius: 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
<mat-card class="cardWithShadow">
|
||||
<mat-card-content>
|
||||
<mat-card-title>Yearly Breakup</mat-card-title>
|
||||
<div class="row m-t-24">
|
||||
<div class="col-7">
|
||||
<h4 class="f-s-24">$36,358</h4>
|
||||
<div class="d-flex align-items-center m-t-16">
|
||||
<button mat-icon-button class="bg-light-success text-success shadow-none icon-27 p-0 d-flex align-items-center justify-content-center">
|
||||
<i-tabler name="arrow-up-right" class="icon-20 d-flex align-items-center"></i-tabler>
|
||||
</button>
|
||||
<div class="f-w-600 m-l-12 f-s-14">+9%</div>
|
||||
<div class="m-l-4 f-s-14">last year</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex align-items-center m-t-32">
|
||||
<div class="d-flex align-items-center">
|
||||
<i-tabler name="circle-filled" class="text-primary icon-12 d-flex"></i-tabler>
|
||||
<div class="m-l-12 f-s-14">2025</div>
|
||||
</div>
|
||||
<div class="d-flex align-items-center m-l-16">
|
||||
<i-tabler name="circle-filled" class="text-light-primary icon-12 d-flex"></i-tabler>
|
||||
<div class="m-l-12 f-s-14">2024</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-5 d-flex align-items-start">
|
||||
<apx-chart [series]="yearlyChart.series" [dataLabels]="yearlyChart.dataLabels"
|
||||
[chart]="yearlyChart.chart" [legend]="yearlyChart.legend" [colors]="yearlyChart.colors"
|
||||
[stroke]="yearlyChart.stroke" [tooltip]="yearlyChart.tooltip"
|
||||
[plotOptions]="yearlyChart.plotOptions" [responsive]="yearlyChart.responsive"></apx-chart>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
<mat-card class="cardWithShadow">
|
||||
<mat-card-content>
|
||||
<mat-card-title>Yearly Breakup</mat-card-title>
|
||||
<div class="row m-t-24">
|
||||
<div class="col-7">
|
||||
<h4 class="f-s-24">$36,358</h4>
|
||||
<div class="d-flex align-items-center m-t-16">
|
||||
<button mat-icon-button class="bg-light-success text-success shadow-none icon-27 p-0 d-flex align-items-center justify-content-center">
|
||||
<i-tabler name="arrow-up-right" class="icon-20 d-flex align-items-center"></i-tabler>
|
||||
</button>
|
||||
<div class="f-w-600 m-l-12 f-s-14">+9%</div>
|
||||
<div class="m-l-4 f-s-14">last year</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex align-items-center m-t-32">
|
||||
<div class="d-flex align-items-center">
|
||||
<i-tabler name="circle-filled" class="text-primary icon-12 d-flex"></i-tabler>
|
||||
<div class="m-l-12 f-s-14">2025</div>
|
||||
</div>
|
||||
<div class="d-flex align-items-center m-l-16">
|
||||
<i-tabler name="circle-filled" class="text-light-primary icon-12 d-flex"></i-tabler>
|
||||
<div class="m-l-12 f-s-14">2024</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-5 d-flex align-items-start">
|
||||
<apx-chart [series]="yearlyChart.series" [dataLabels]="yearlyChart.dataLabels"
|
||||
[chart]="yearlyChart.chart" [legend]="yearlyChart.legend" [colors]="yearlyChart.colors"
|
||||
[stroke]="yearlyChart.stroke" [tooltip]="yearlyChart.tooltip"
|
||||
[plotOptions]="yearlyChart.plotOptions" [responsive]="yearlyChart.responsive"></apx-chart>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
@@ -1,101 +1,101 @@
|
||||
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
|
||||
import { TablerIconsModule } from 'angular-tabler-icons';
|
||||
import {
|
||||
ApexChart,
|
||||
ChartComponent,
|
||||
ApexDataLabels,
|
||||
ApexLegend,
|
||||
ApexStroke,
|
||||
ApexTooltip,
|
||||
ApexAxisChartSeries,
|
||||
ApexXAxis,
|
||||
ApexYAxis,
|
||||
ApexGrid,
|
||||
ApexPlotOptions,
|
||||
ApexFill,
|
||||
ApexMarkers,
|
||||
ApexResponsive,
|
||||
NgApexchartsModule,
|
||||
} from 'ng-apexcharts';
|
||||
import { MaterialModule } from 'src/app/material.module';
|
||||
|
||||
|
||||
export interface yearlyChart {
|
||||
series: ApexAxisChartSeries;
|
||||
chart: ApexChart;
|
||||
dataLabels: ApexDataLabels;
|
||||
plotOptions: ApexPlotOptions;
|
||||
tooltip: ApexTooltip;
|
||||
stroke: ApexStroke;
|
||||
legend: ApexLegend;
|
||||
responsive: ApexResponsive;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-yearly-breakup',
|
||||
templateUrl: './yearly-breakup.component.html',
|
||||
imports: [MaterialModule, NgApexchartsModule, TablerIconsModule],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
})
|
||||
export class AppYearlyBreakupComponent {
|
||||
@ViewChild('chart') chart: ChartComponent = Object.create(null);
|
||||
|
||||
public yearlyChart!: Partial<yearlyChart> | any;
|
||||
|
||||
|
||||
constructor() {
|
||||
|
||||
this.yearlyChart = {
|
||||
|
||||
color: "#adb5bd",
|
||||
series: [38, 40, 25],
|
||||
labels: ["2025", "2024", "2023"],
|
||||
chart: {
|
||||
width: 125,
|
||||
type: "donut",
|
||||
fontFamily: "inherit",
|
||||
foreColor: "#adb0bb",
|
||||
},
|
||||
plotOptions: {
|
||||
pie: {
|
||||
startAngle: 0,
|
||||
endAngle: 360,
|
||||
donut: {
|
||||
size: "75%",
|
||||
},
|
||||
},
|
||||
},
|
||||
stroke: {
|
||||
show: false,
|
||||
},
|
||||
|
||||
dataLabels: {
|
||||
enabled: false,
|
||||
},
|
||||
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
colors: ['#5D87FF', '#ECF2FF', '#F9F9FD'],
|
||||
|
||||
responsive: [
|
||||
{
|
||||
breakpoint: 991,
|
||||
options: {
|
||||
chart: {
|
||||
width: 120,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
tooltip: {
|
||||
theme: "dark",
|
||||
fillSeriesColor: false,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
import { Component, ViewEncapsulation, ViewChild } from '@angular/core';
|
||||
import { TablerIconsModule } from 'angular-tabler-icons';
|
||||
import {
|
||||
ApexChart,
|
||||
ChartComponent,
|
||||
ApexDataLabels,
|
||||
ApexLegend,
|
||||
ApexStroke,
|
||||
ApexTooltip,
|
||||
ApexAxisChartSeries,
|
||||
ApexXAxis,
|
||||
ApexYAxis,
|
||||
ApexGrid,
|
||||
ApexPlotOptions,
|
||||
ApexFill,
|
||||
ApexMarkers,
|
||||
ApexResponsive,
|
||||
NgApexchartsModule,
|
||||
} from 'ng-apexcharts';
|
||||
import { MaterialModule } from 'src/app/material.module';
|
||||
|
||||
|
||||
export interface yearlyChart {
|
||||
series: ApexAxisChartSeries;
|
||||
chart: ApexChart;
|
||||
dataLabels: ApexDataLabels;
|
||||
plotOptions: ApexPlotOptions;
|
||||
tooltip: ApexTooltip;
|
||||
stroke: ApexStroke;
|
||||
legend: ApexLegend;
|
||||
responsive: ApexResponsive;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-yearly-breakup',
|
||||
templateUrl: './yearly-breakup.component.html',
|
||||
imports: [MaterialModule, NgApexchartsModule, TablerIconsModule],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
})
|
||||
export class AppYearlyBreakupComponent {
|
||||
@ViewChild('chart') chart: ChartComponent = Object.create(null);
|
||||
|
||||
public yearlyChart!: Partial<yearlyChart> | any;
|
||||
|
||||
|
||||
constructor() {
|
||||
|
||||
this.yearlyChart = {
|
||||
|
||||
color: "#adb5bd",
|
||||
series: [38, 40, 25],
|
||||
labels: ["2025", "2024", "2023"],
|
||||
chart: {
|
||||
width: 125,
|
||||
type: "donut",
|
||||
fontFamily: "inherit",
|
||||
foreColor: "#adb0bb",
|
||||
},
|
||||
plotOptions: {
|
||||
pie: {
|
||||
startAngle: 0,
|
||||
endAngle: 360,
|
||||
donut: {
|
||||
size: "75%",
|
||||
},
|
||||
},
|
||||
},
|
||||
stroke: {
|
||||
show: false,
|
||||
},
|
||||
|
||||
dataLabels: {
|
||||
enabled: false,
|
||||
},
|
||||
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
colors: ['#5D87FF', '#ECF2FF', '#F9F9FD'],
|
||||
|
||||
responsive: [
|
||||
{
|
||||
breakpoint: 991,
|
||||
options: {
|
||||
chart: {
|
||||
width: 120,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
tooltip: {
|
||||
theme: "dark",
|
||||
fillSeriesColor: false,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
export interface AppSettings {
|
||||
|
||||
sidenavOpened: boolean;
|
||||
sidenavCollapsed: boolean;
|
||||
|
||||
}
|
||||
|
||||
export const defaults: AppSettings = {
|
||||
sidenavOpened: true,
|
||||
sidenavCollapsed: true,
|
||||
};
|
||||
export interface AppSettings {
|
||||
|
||||
sidenavOpened: boolean;
|
||||
sidenavCollapsed: boolean;
|
||||
|
||||
}
|
||||
|
||||
export const defaults: AppSettings = {
|
||||
sidenavOpened: true,
|
||||
sidenavCollapsed: true,
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!-- ============================================================== -->
|
||||
<!-- Only router without any element -->
|
||||
<!-- ============================================================== -->
|
||||
<mat-sidenav-container dir="ltr" class="light-theme">
|
||||
<router-outlet></router-outlet>
|
||||
<!-- ============================================================== -->
|
||||
<!-- Only router without any element -->
|
||||
<!-- ============================================================== -->
|
||||
<mat-sidenav-container dir="ltr" class="light-theme">
|
||||
<router-outlet></router-outlet>
|
||||
</mat-sidenav-container>
|
||||
@@ -1,23 +1,23 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { CoreService } from 'src/app/services/core.service';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterOutlet } from '@angular/router';
|
||||
import { MaterialModule } from 'src/app/material.module';
|
||||
|
||||
@Component({
|
||||
selector: 'app-blank',
|
||||
templateUrl: './blank.component.html',
|
||||
styleUrls: [],
|
||||
imports: [RouterOutlet, MaterialModule, CommonModule],
|
||||
})
|
||||
export class BlankComponent {
|
||||
private htmlElement!: HTMLHtmlElement;
|
||||
|
||||
options = this.settings.getOptions();
|
||||
|
||||
constructor(private settings: CoreService) {
|
||||
this.htmlElement = document.querySelector('html')!;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
import { Component } from '@angular/core';
|
||||
import { CoreService } from 'src/app/services/core.service';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterOutlet } from '@angular/router';
|
||||
import { MaterialModule } from 'src/app/material.module';
|
||||
|
||||
@Component({
|
||||
selector: 'app-blank',
|
||||
templateUrl: './blank.component.html',
|
||||
styleUrls: [],
|
||||
imports: [RouterOutlet, MaterialModule, CommonModule],
|
||||
})
|
||||
export class BlankComponent {
|
||||
private htmlElement!: HTMLHtmlElement;
|
||||
|
||||
options = this.settings.getOptions();
|
||||
|
||||
constructor(private settings: CoreService) {
|
||||
this.htmlElement = document.querySelector('html')!;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,59 +1,59 @@
|
||||
|
||||
<app-topstrip></app-topstrip>
|
||||
<mat-sidenav-container class="mainWrapper blue_theme light-theme" autosize autoFocus dir="ltr">
|
||||
<!-- ============================================================== -->
|
||||
<!-- Vertical Sidebar -->
|
||||
<!-- ============================================================== -->
|
||||
<mat-sidenav #leftsidenav [mode]="isOver ? 'over' : 'side'" [opened]="!isOver"
|
||||
(openedChange)="onSidenavOpenedChange($event)" (closedStart)="onSidenavClosedStart()" class="sidebarNav">
|
||||
<div class="flex-layout">
|
||||
<app-sidebar (toggleMobileNav)="sidenav.toggle()" [showToggle]="isOver"></app-sidebar>
|
||||
<ng-scrollbar class="position-relative" style="height: 100%">
|
||||
<mat-nav-list class="sidebar-list">
|
||||
@for(item of navItems; track item) {
|
||||
<app-nav-item [item]="item" (notify)="sidenav.toggle()">
|
||||
</app-nav-item>
|
||||
}
|
||||
</mat-nav-list>
|
||||
</ng-scrollbar>
|
||||
<div class="p-24">
|
||||
<div class="bg-light-secondary d-flex align-items-center gap-4 rounded p-20 m-t-20">
|
||||
<div>
|
||||
<h5 class="f-s-16 f-w-600 m-b-8">
|
||||
Check Pro <br> Version
|
||||
</h5>
|
||||
<a mat-flat-button
|
||||
href="https://adminmart.com/product/modernize-angular-material-dashboard/?ref=56#product-demo-section" target="_blank"
|
||||
class="d-flex justify-content-center bg-secondary">
|
||||
Check
|
||||
</a>
|
||||
</div>
|
||||
<img src="/assets/images/backgrounds/rocket.png" alt="imgae" class="side-img m-t--48 m-r--8" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-sidenav>
|
||||
|
||||
<!-- ============================================================== -->
|
||||
<!-- Main Content -->
|
||||
<!-- ============================================================== -->
|
||||
<mat-sidenav-content class="contentWrapper" #content>
|
||||
<!-- ============================================================== -->
|
||||
<!-- VerticalHeader -->
|
||||
<!-- ============================================================== -->
|
||||
|
||||
<app-header [showToggle]="!isOver" (toggleMobileNav)="sidenav.toggle()"></app-header>
|
||||
|
||||
<main class="pageWrapper maxWidth">
|
||||
<!-- ============================================================== -->
|
||||
<!-- Outlet -->
|
||||
<!-- ============================================================== -->
|
||||
<router-outlet></router-outlet>
|
||||
</main>
|
||||
|
||||
<div class="p-16 p-b-30 text-center">
|
||||
Design & Developed by <a class="text-decoration-none" href="https://adminmart.com/" target="_blank">AdminMart.com</a>
|
||||
</div>
|
||||
</mat-sidenav-content>
|
||||
|
||||
|
||||
<app-topstrip></app-topstrip>
|
||||
<mat-sidenav-container class="mainWrapper blue_theme light-theme" autosize autoFocus dir="ltr">
|
||||
<!-- ============================================================== -->
|
||||
<!-- Vertical Sidebar -->
|
||||
<!-- ============================================================== -->
|
||||
<mat-sidenav #leftsidenav [mode]="isOver ? 'over' : 'side'" [opened]="!isOver"
|
||||
(openedChange)="onSidenavOpenedChange($event)" (closedStart)="onSidenavClosedStart()" class="sidebarNav">
|
||||
<div class="flex-layout">
|
||||
<app-sidebar (toggleMobileNav)="sidenav.toggle()" [showToggle]="isOver"></app-sidebar>
|
||||
<ng-scrollbar class="position-relative" style="height: 100%">
|
||||
<mat-nav-list class="sidebar-list">
|
||||
@for(item of navItems; track item) {
|
||||
<app-nav-item [item]="item" (notify)="sidenav.toggle()">
|
||||
</app-nav-item>
|
||||
}
|
||||
</mat-nav-list>
|
||||
</ng-scrollbar>
|
||||
<div class="p-24">
|
||||
<div class="bg-light-secondary d-flex align-items-center gap-4 rounded p-20 m-t-20">
|
||||
<div>
|
||||
<h5 class="f-s-16 f-w-600 m-b-8">
|
||||
Check Pro <br> Version
|
||||
</h5>
|
||||
<a mat-flat-button
|
||||
href="https://adminmart.com/product/modernize-angular-material-dashboard/?ref=56#product-demo-section" target="_blank"
|
||||
class="d-flex justify-content-center bg-secondary">
|
||||
Check
|
||||
</a>
|
||||
</div>
|
||||
<img src="/assets/images/backgrounds/rocket.png" alt="imgae" class="side-img m-t--48 m-r--8" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-sidenav>
|
||||
|
||||
<!-- ============================================================== -->
|
||||
<!-- Main Content -->
|
||||
<!-- ============================================================== -->
|
||||
<mat-sidenav-content class="contentWrapper" #content>
|
||||
<!-- ============================================================== -->
|
||||
<!-- VerticalHeader -->
|
||||
<!-- ============================================================== -->
|
||||
|
||||
<app-header [showToggle]="!isOver" (toggleMobileNav)="sidenav.toggle()"></app-header>
|
||||
|
||||
<main class="pageWrapper maxWidth">
|
||||
<!-- ============================================================== -->
|
||||
<!-- Outlet -->
|
||||
<!-- ============================================================== -->
|
||||
<router-outlet></router-outlet>
|
||||
</main>
|
||||
|
||||
<div class="p-16 p-b-30 text-center">
|
||||
Design & Developed by <a class="text-decoration-none" href="https://adminmart.com/" target="_blank">AdminMart.com</a>
|
||||
</div>
|
||||
</mat-sidenav-content>
|
||||
|
||||
</mat-sidenav-container>
|
||||
@@ -1,117 +1,117 @@
|
||||
import { BreakpointObserver, MediaMatcher } from '@angular/cdk/layout';
|
||||
import { Component, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { MatSidenav, MatSidenavContent } from '@angular/material/sidenav';
|
||||
import { CoreService } from 'src/app/services/core.service';
|
||||
|
||||
import { filter } from 'rxjs/operators';
|
||||
import { NavigationEnd, Router } from '@angular/router';
|
||||
import { NavService } from '../../services/nav.service';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { MaterialModule } from 'src/app/material.module';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgScrollbarModule } from 'ngx-scrollbar';
|
||||
import { TablerIconsModule } from 'angular-tabler-icons';
|
||||
import { HeaderComponent } from './header/header.component';
|
||||
import { SidebarComponent } from './sidebar/sidebar.component';
|
||||
import { AppNavItemComponent } from './sidebar/nav-item/nav-item.component';
|
||||
import { navItems } from './sidebar/sidebar-data';
|
||||
import { AppTopstripComponent } from './top-strip/topstrip.component';
|
||||
|
||||
|
||||
const MOBILE_VIEW = 'screen and (max-width: 768px)';
|
||||
const TABLET_VIEW = 'screen and (min-width: 769px) and (max-width: 1024px)';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-full',
|
||||
imports: [
|
||||
RouterModule,
|
||||
AppNavItemComponent,
|
||||
MaterialModule,
|
||||
CommonModule,
|
||||
SidebarComponent,
|
||||
NgScrollbarModule,
|
||||
TablerIconsModule,
|
||||
HeaderComponent,
|
||||
AppTopstripComponent
|
||||
],
|
||||
templateUrl: './full.component.html',
|
||||
styleUrls: [],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class FullComponent implements OnInit {
|
||||
navItems = navItems;
|
||||
|
||||
@ViewChild('leftsidenav')
|
||||
public sidenav: MatSidenav;
|
||||
resView = false;
|
||||
@ViewChild('content', { static: true }) content!: MatSidenavContent;
|
||||
//get options from service
|
||||
options = this.settings.getOptions();
|
||||
private layoutChangesSubscription = Subscription.EMPTY;
|
||||
private isMobileScreen = false;
|
||||
private isContentWidthFixed = true;
|
||||
private isCollapsedWidthFixed = false;
|
||||
private htmlElement!: HTMLHtmlElement;
|
||||
|
||||
get isOver(): boolean {
|
||||
return this.isMobileScreen;
|
||||
}
|
||||
|
||||
|
||||
constructor(
|
||||
private settings: CoreService,
|
||||
private router: Router,
|
||||
private breakpointObserver: BreakpointObserver,
|
||||
) {
|
||||
this.htmlElement = document.querySelector('html')!;
|
||||
this.layoutChangesSubscription = this.breakpointObserver
|
||||
.observe([MOBILE_VIEW, TABLET_VIEW])
|
||||
.subscribe((state) => {
|
||||
// SidenavOpened must be reset true when layout changes
|
||||
this.options.sidenavOpened = true;
|
||||
this.isMobileScreen = state.breakpoints[MOBILE_VIEW];
|
||||
if (this.options.sidenavCollapsed == false) {
|
||||
this.options.sidenavCollapsed = state.breakpoints[TABLET_VIEW];
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize project theme with options
|
||||
|
||||
|
||||
// This is for scroll to top
|
||||
this.router.events
|
||||
.pipe(filter((event) => event instanceof NavigationEnd))
|
||||
.subscribe((e) => {
|
||||
this.content.scrollTo({ top: 0 });
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void { }
|
||||
|
||||
ngOnDestroy() {
|
||||
this.layoutChangesSubscription.unsubscribe();
|
||||
}
|
||||
|
||||
toggleCollapsed() {
|
||||
this.isContentWidthFixed = false;
|
||||
this.options.sidenavCollapsed = !this.options.sidenavCollapsed;
|
||||
this.resetCollapsedState();
|
||||
}
|
||||
|
||||
resetCollapsedState(timer = 400) {
|
||||
setTimeout(() => this.settings.setOptions(this.options), timer);
|
||||
}
|
||||
|
||||
onSidenavClosedStart() {
|
||||
this.isContentWidthFixed = false;
|
||||
}
|
||||
|
||||
onSidenavOpenedChange(isOpened: boolean) {
|
||||
this.isCollapsedWidthFixed = !this.isOver;
|
||||
this.options.sidenavOpened = isOpened;
|
||||
//this.settings.setOptions(this.options);
|
||||
}
|
||||
|
||||
}
|
||||
import { BreakpointObserver, MediaMatcher } from '@angular/cdk/layout';
|
||||
import { Component, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { MatSidenav, MatSidenavContent } from '@angular/material/sidenav';
|
||||
import { CoreService } from 'src/app/services/core.service';
|
||||
|
||||
import { filter } from 'rxjs/operators';
|
||||
import { NavigationEnd, Router } from '@angular/router';
|
||||
import { NavService } from '../../services/nav.service';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { MaterialModule } from 'src/app/material.module';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgScrollbarModule } from 'ngx-scrollbar';
|
||||
import { TablerIconsModule } from 'angular-tabler-icons';
|
||||
import { HeaderComponent } from './header/header.component';
|
||||
import { SidebarComponent } from './sidebar/sidebar.component';
|
||||
import { AppNavItemComponent } from './sidebar/nav-item/nav-item.component';
|
||||
import { navItems } from './sidebar/sidebar-data';
|
||||
import { AppTopstripComponent } from './top-strip/topstrip.component';
|
||||
|
||||
|
||||
const MOBILE_VIEW = 'screen and (max-width: 768px)';
|
||||
const TABLET_VIEW = 'screen and (min-width: 769px) and (max-width: 1024px)';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-full',
|
||||
imports: [
|
||||
RouterModule,
|
||||
AppNavItemComponent,
|
||||
MaterialModule,
|
||||
CommonModule,
|
||||
SidebarComponent,
|
||||
NgScrollbarModule,
|
||||
TablerIconsModule,
|
||||
HeaderComponent,
|
||||
AppTopstripComponent
|
||||
],
|
||||
templateUrl: './full.component.html',
|
||||
styleUrls: [],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class FullComponent implements OnInit {
|
||||
navItems = navItems;
|
||||
|
||||
@ViewChild('leftsidenav')
|
||||
public sidenav: MatSidenav;
|
||||
resView = false;
|
||||
@ViewChild('content', { static: true }) content!: MatSidenavContent;
|
||||
//get options from service
|
||||
options = this.settings.getOptions();
|
||||
private layoutChangesSubscription = Subscription.EMPTY;
|
||||
private isMobileScreen = false;
|
||||
private isContentWidthFixed = true;
|
||||
private isCollapsedWidthFixed = false;
|
||||
private htmlElement!: HTMLHtmlElement;
|
||||
|
||||
get isOver(): boolean {
|
||||
return this.isMobileScreen;
|
||||
}
|
||||
|
||||
|
||||
constructor(
|
||||
private settings: CoreService,
|
||||
private router: Router,
|
||||
private breakpointObserver: BreakpointObserver,
|
||||
) {
|
||||
this.htmlElement = document.querySelector('html')!;
|
||||
this.layoutChangesSubscription = this.breakpointObserver
|
||||
.observe([MOBILE_VIEW, TABLET_VIEW])
|
||||
.subscribe((state) => {
|
||||
// SidenavOpened must be reset true when layout changes
|
||||
this.options.sidenavOpened = true;
|
||||
this.isMobileScreen = state.breakpoints[MOBILE_VIEW];
|
||||
if (this.options.sidenavCollapsed == false) {
|
||||
this.options.sidenavCollapsed = state.breakpoints[TABLET_VIEW];
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize project theme with options
|
||||
|
||||
|
||||
// This is for scroll to top
|
||||
this.router.events
|
||||
.pipe(filter((event) => event instanceof NavigationEnd))
|
||||
.subscribe((e) => {
|
||||
this.content.scrollTo({ top: 0 });
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void { }
|
||||
|
||||
ngOnDestroy() {
|
||||
this.layoutChangesSubscription.unsubscribe();
|
||||
}
|
||||
|
||||
toggleCollapsed() {
|
||||
this.isContentWidthFixed = false;
|
||||
this.options.sidenavCollapsed = !this.options.sidenavCollapsed;
|
||||
this.resetCollapsedState();
|
||||
}
|
||||
|
||||
resetCollapsedState(timer = 400) {
|
||||
setTimeout(() => this.settings.setOptions(this.options), timer);
|
||||
}
|
||||
|
||||
onSidenavClosedStart() {
|
||||
this.isContentWidthFixed = false;
|
||||
}
|
||||
|
||||
onSidenavOpenedChange(isOpened: boolean) {
|
||||
this.isCollapsedWidthFixed = !this.isOver;
|
||||
this.options.sidenavOpened = isOpened;
|
||||
//this.settings.setOptions(this.options);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,48 +1,48 @@
|
||||
<mat-toolbar class="topbar gap-10">
|
||||
|
||||
<!-- Mobile Menu -->
|
||||
|
||||
<button mat-icon-button (click)="toggleMobileNav.emit()" class="d-flex d-lg-none justify-content-center">
|
||||
<i-tabler name="menu-2" class="icon-20 d-flex"></i-tabler>
|
||||
</button>
|
||||
|
||||
<button mat-icon-button [matMenuTriggerFor]="menu" aria-label="Notifications">
|
||||
<i-tabler class="d-flex" name="bell" matBadge="1" matBadgeColor="primary"></i-tabler>
|
||||
</button>
|
||||
<mat-menu #menu="matMenu">
|
||||
<button mat-menu-item>Item 1</button>
|
||||
<button mat-menu-item>Item 2</button>
|
||||
</mat-menu>
|
||||
|
||||
|
||||
<span class="flex-1-auto"></span>
|
||||
|
||||
<!-- --------------------------------------------------------------- -->
|
||||
<!-- profile Dropdown -->
|
||||
<!-- --------------------------------------------------------------- -->
|
||||
<a mat-flat-button href="https://adminmart.com/product/modernize-angular-admin-dashboard/?ref=56#product-demo-section"
|
||||
target="_blank" class="d-flex justify-content-center bg-success">
|
||||
Check Pro Template
|
||||
</a>
|
||||
<button mat-mini-fab [matMenuTriggerFor]="profilemenu" aria-label="Notifications">
|
||||
<img src="/assets/images/profile/user-1.jpg" class="rounded-circle object-cover d-block" width="35" />
|
||||
</button>
|
||||
<mat-menu #profilemenu="matMenu" class="cardWithShadow topbar-dd">
|
||||
<button mat-menu-item>
|
||||
<mat-icon class="d-flex align-items-center"><i-tabler name="user" class="icon-18 d-flex"></i-tabler></mat-icon>My
|
||||
Profile
|
||||
</button>
|
||||
<button mat-menu-item>
|
||||
<mat-icon class="d-flex align-items-center"><i-tabler name="mail" class="icon-18 d-flex"></i-tabler></mat-icon>My
|
||||
Account
|
||||
</button>
|
||||
<button mat-menu-item>
|
||||
<mat-icon class="d-flex align-items-center"><i-tabler name="list-check"
|
||||
class="icon-18 d-flex"></i-tabler></mat-icon>My Task
|
||||
</button>
|
||||
|
||||
<div class="p-x-12 m-t-12">
|
||||
<a [routerLink]="['/authentication/login']" mat-stroked-button class="w-100">Logout</a>
|
||||
</div>
|
||||
</mat-menu>
|
||||
<mat-toolbar class="topbar gap-10">
|
||||
|
||||
<!-- Mobile Menu -->
|
||||
|
||||
<button mat-icon-button (click)="toggleMobileNav.emit()" class="d-flex d-lg-none justify-content-center">
|
||||
<i-tabler name="menu-2" class="icon-20 d-flex"></i-tabler>
|
||||
</button>
|
||||
|
||||
<button mat-icon-button [matMenuTriggerFor]="menu" aria-label="Notifications">
|
||||
<i-tabler class="d-flex" name="bell" matBadge="1" matBadgeColor="primary"></i-tabler>
|
||||
</button>
|
||||
<mat-menu #menu="matMenu">
|
||||
<button mat-menu-item>Item 1</button>
|
||||
<button mat-menu-item>Item 2</button>
|
||||
</mat-menu>
|
||||
|
||||
|
||||
<span class="flex-1-auto"></span>
|
||||
|
||||
<!-- --------------------------------------------------------------- -->
|
||||
<!-- profile Dropdown -->
|
||||
<!-- --------------------------------------------------------------- -->
|
||||
<a mat-flat-button href="https://adminmart.com/product/modernize-angular-admin-dashboard/?ref=56#product-demo-section"
|
||||
target="_blank" class="d-flex justify-content-center bg-success">
|
||||
Check Pro Template
|
||||
</a>
|
||||
<button mat-mini-fab [matMenuTriggerFor]="profilemenu" aria-label="Notifications">
|
||||
<img src="/assets/images/profile/user-1.jpg" class="rounded-circle object-cover d-block" width="35" />
|
||||
</button>
|
||||
<mat-menu #profilemenu="matMenu" class="cardWithShadow topbar-dd">
|
||||
<button mat-menu-item>
|
||||
<mat-icon class="d-flex align-items-center"><i-tabler name="user" class="icon-18 d-flex"></i-tabler></mat-icon>My
|
||||
Profile
|
||||
</button>
|
||||
<button mat-menu-item>
|
||||
<mat-icon class="d-flex align-items-center"><i-tabler name="mail" class="icon-18 d-flex"></i-tabler></mat-icon>My
|
||||
Account
|
||||
</button>
|
||||
<button mat-menu-item>
|
||||
<mat-icon class="d-flex align-items-center"><i-tabler name="list-check"
|
||||
class="icon-18 d-flex"></i-tabler></mat-icon>My Task
|
||||
</button>
|
||||
|
||||
<div class="p-x-12 m-t-12">
|
||||
<a [routerLink]="['/authentication/login']" mat-stroked-button class="w-100">Logout</a>
|
||||
</div>
|
||||
</mat-menu>
|
||||
</mat-toolbar>
|
||||
@@ -1,30 +1,30 @@
|
||||
import {
|
||||
Component,
|
||||
Output,
|
||||
EventEmitter,
|
||||
Input,
|
||||
ViewEncapsulation,
|
||||
} from '@angular/core';
|
||||
import { TablerIconsModule } from 'angular-tabler-icons';
|
||||
import { MaterialModule } from 'src/app/material.module';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgScrollbarModule } from 'ngx-scrollbar';
|
||||
|
||||
@Component({
|
||||
selector: 'app-header',
|
||||
imports: [
|
||||
RouterModule,
|
||||
CommonModule,
|
||||
NgScrollbarModule,
|
||||
TablerIconsModule,
|
||||
MaterialModule,
|
||||
],
|
||||
templateUrl: './header.component.html',
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
})
|
||||
export class HeaderComponent {
|
||||
@Input() showToggle = true;
|
||||
@Input() toggleChecked = false;
|
||||
@Output() toggleMobileNav = new EventEmitter<void>();
|
||||
import {
|
||||
Component,
|
||||
Output,
|
||||
EventEmitter,
|
||||
Input,
|
||||
ViewEncapsulation,
|
||||
} from '@angular/core';
|
||||
import { TablerIconsModule } from 'angular-tabler-icons';
|
||||
import { MaterialModule } from 'src/app/material.module';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgScrollbarModule } from 'ngx-scrollbar';
|
||||
|
||||
@Component({
|
||||
selector: 'app-header',
|
||||
imports: [
|
||||
RouterModule,
|
||||
CommonModule,
|
||||
NgScrollbarModule,
|
||||
TablerIconsModule,
|
||||
MaterialModule,
|
||||
],
|
||||
templateUrl: './header.component.html',
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
})
|
||||
export class HeaderComponent {
|
||||
@Input() showToggle = true;
|
||||
@Input() toggleChecked = false;
|
||||
@Output() toggleMobileNav = new EventEmitter<void>();
|
||||
}
|
||||
@@ -1,20 +1,20 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { CoreService } from 'src/app/services/core.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-branding',
|
||||
imports: [],
|
||||
template: `
|
||||
<a href="/" class="logodark">
|
||||
<img
|
||||
src="./assets/images/logos/dark-logo.svg"
|
||||
class="align-middle m-2"
|
||||
alt="logo"
|
||||
/>
|
||||
</a>
|
||||
`,
|
||||
})
|
||||
export class BrandingComponent {
|
||||
options = this.settings.getOptions();
|
||||
constructor(private settings: CoreService) {}
|
||||
}
|
||||
import { Component } from '@angular/core';
|
||||
import { CoreService } from 'src/app/services/core.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-branding',
|
||||
imports: [],
|
||||
template: `
|
||||
<a href="/" class="logodark">
|
||||
<img
|
||||
src="./assets/images/logos/dark-logo.svg"
|
||||
class="align-middle m-2"
|
||||
alt="logo"
|
||||
/>
|
||||
</a>
|
||||
`,
|
||||
})
|
||||
export class BrandingComponent {
|
||||
options = this.settings.getOptions();
|
||||
constructor(private settings: CoreService) {}
|
||||
}
|
||||
|
||||
@@ -1,48 +1,48 @@
|
||||
@if(item.navCap){
|
||||
<div mat-subheader class="nav-caption">
|
||||
{{ item.navCap }}
|
||||
</div>
|
||||
} @if(!item.navCap && !item.external) {
|
||||
<a mat-list-item (click)="onItemSelected(item)" [ngClass]="{
|
||||
activeMenu: item.route ? router.isActive(item.route, true) : false,
|
||||
expanded: expanded,
|
||||
disabled: item.disabled
|
||||
}" class="menu-list-item">
|
||||
<i-tabler class="routeIcon" name="{{ item.iconName }}" matListItemIcon></i-tabler>
|
||||
<span class="hide-menu">{{ item.displayName }}</span>
|
||||
|
||||
@if(item.children && item.children.length) {
|
||||
<span class="arrow-icon" fxFlex>
|
||||
<span fxFlex></span>
|
||||
@if(item.chip) {
|
||||
<span>
|
||||
<span class="{{ item.chipClass }} p-x-8 p-y-4 item-chip f-w-500 rounded-pill ">{{ item.chipContent }}</span>
|
||||
</span>
|
||||
}
|
||||
<mat-icon [@indicatorRotate]="expanded ? 'expanded' : 'collapsed'">
|
||||
expand_more
|
||||
</mat-icon>
|
||||
</span>
|
||||
}
|
||||
</a>
|
||||
}
|
||||
|
||||
<!-- external Link -->
|
||||
|
||||
@if(!item.navCap && item.external) {
|
||||
<mat-list-item (click)="openExternalLink(item.route)" class="menu-list-item" target="_blank">
|
||||
<i-tabler class="routeIcon" name="{{ item.iconName }}" matListItemIcon></i-tabler>
|
||||
<span class="hide-menu">{{ item.displayName }} </span>
|
||||
@if(item.chip) {
|
||||
<span>
|
||||
<span class="{{ item.chipClass }} p-x-8 p-y-4 item-chip f-w-500 rounded-pill ">{{ item.chipContent }}</span>
|
||||
</span>
|
||||
}
|
||||
</mat-list-item>
|
||||
}
|
||||
|
||||
<!-- children -->
|
||||
@if(expanded) { @for(child of item.children; track child) {
|
||||
<app-nav-item [item]="child" (click)="onSubItemSelected(child)" [depth]="depth + 1">
|
||||
</app-nav-item>
|
||||
@if(item.navCap){
|
||||
<div mat-subheader class="nav-caption">
|
||||
{{ item.navCap }}
|
||||
</div>
|
||||
} @if(!item.navCap && !item.external) {
|
||||
<a mat-list-item (click)="onItemSelected(item)" [ngClass]="{
|
||||
activeMenu: item.route ? router.isActive(item.route, true) : false,
|
||||
expanded: expanded,
|
||||
disabled: item.disabled
|
||||
}" class="menu-list-item">
|
||||
<i-tabler class="routeIcon" name="{{ item.iconName }}" matListItemIcon></i-tabler>
|
||||
<span class="hide-menu">{{ item.displayName }}</span>
|
||||
|
||||
@if(item.children && item.children.length) {
|
||||
<span class="arrow-icon" fxFlex>
|
||||
<span fxFlex></span>
|
||||
@if(item.chip) {
|
||||
<span>
|
||||
<span class="{{ item.chipClass }} p-x-8 p-y-4 item-chip f-w-500 rounded-pill ">{{ item.chipContent }}</span>
|
||||
</span>
|
||||
}
|
||||
<mat-icon [@indicatorRotate]="expanded ? 'expanded' : 'collapsed'">
|
||||
expand_more
|
||||
</mat-icon>
|
||||
</span>
|
||||
}
|
||||
</a>
|
||||
}
|
||||
|
||||
<!-- external Link -->
|
||||
|
||||
@if(!item.navCap && item.external) {
|
||||
<mat-list-item (click)="openExternalLink(item.route)" class="menu-list-item" target="_blank">
|
||||
<i-tabler class="routeIcon" name="{{ item.iconName }}" matListItemIcon></i-tabler>
|
||||
<span class="hide-menu">{{ item.displayName }} </span>
|
||||
@if(item.chip) {
|
||||
<span>
|
||||
<span class="{{ item.chipClass }} p-x-8 p-y-4 item-chip f-w-500 rounded-pill ">{{ item.chipContent }}</span>
|
||||
</span>
|
||||
}
|
||||
</mat-list-item>
|
||||
}
|
||||
|
||||
<!-- children -->
|
||||
@if(expanded) { @for(child of item.children; track child) {
|
||||
<app-nav-item [item]="child" (click)="onSubItemSelected(child)" [depth]="depth + 1">
|
||||
</app-nav-item>
|
||||
} }
|
||||
@@ -1,77 +1,77 @@
|
||||
import {
|
||||
Component,
|
||||
HostBinding,
|
||||
Input,
|
||||
OnChanges,
|
||||
Output,
|
||||
EventEmitter,
|
||||
} from '@angular/core';
|
||||
import { NavItem } from './nav-item';
|
||||
import { Router } from '@angular/router';
|
||||
import { NavService } from '../../../../services/nav.service';
|
||||
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { TablerIconsModule } from 'angular-tabler-icons';
|
||||
import { MaterialModule } from 'src/app/material.module';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
selector: 'app-nav-item',
|
||||
imports: [TranslateModule, TablerIconsModule, MaterialModule, CommonModule],
|
||||
templateUrl: './nav-item.component.html',
|
||||
styleUrls: [],
|
||||
})
|
||||
export class AppNavItemComponent implements OnChanges {
|
||||
@Output() notify: EventEmitter<boolean> = new EventEmitter<boolean>();
|
||||
|
||||
@Input() item: NavItem | any;
|
||||
|
||||
expanded: any = false;
|
||||
|
||||
@HostBinding('attr.aria-expanded') ariaExpanded = this.expanded;
|
||||
@Input() depth: any;
|
||||
|
||||
constructor(public navService: NavService, public router: Router) {}
|
||||
|
||||
ngOnChanges() {
|
||||
const url = this.navService.currentUrl();
|
||||
if (this.item.route && url) {
|
||||
this.expanded = url.indexOf(`/${this.item.route}`) === 0;
|
||||
this.ariaExpanded = this.expanded;
|
||||
}
|
||||
}
|
||||
|
||||
onItemSelected(item: NavItem) {
|
||||
if (!item.children || !item.children.length) {
|
||||
this.router.navigate([item.route]);
|
||||
}
|
||||
if (item.children && item.children.length) {
|
||||
this.expanded = !this.expanded;
|
||||
}
|
||||
//scroll
|
||||
window.scroll({
|
||||
top: 0,
|
||||
left: 0,
|
||||
behavior: 'smooth',
|
||||
});
|
||||
if (!this.expanded) {
|
||||
if (window.innerWidth < 1024) {
|
||||
this.notify.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
openExternalLink(url: string): void {
|
||||
if (url) {
|
||||
window.open(url, '_blank');
|
||||
}
|
||||
}
|
||||
|
||||
onSubItemSelected(item: NavItem) {
|
||||
if (!item.children || !item.children.length) {
|
||||
if (this.expanded && window.innerWidth < 1024) {
|
||||
this.notify.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
import {
|
||||
Component,
|
||||
HostBinding,
|
||||
Input,
|
||||
OnChanges,
|
||||
Output,
|
||||
EventEmitter,
|
||||
} from '@angular/core';
|
||||
import { NavItem } from './nav-item';
|
||||
import { Router } from '@angular/router';
|
||||
import { NavService } from '../../../../services/nav.service';
|
||||
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { TablerIconsModule } from 'angular-tabler-icons';
|
||||
import { MaterialModule } from 'src/app/material.module';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
selector: 'app-nav-item',
|
||||
imports: [TranslateModule, TablerIconsModule, MaterialModule, CommonModule],
|
||||
templateUrl: './nav-item.component.html',
|
||||
styleUrls: [],
|
||||
})
|
||||
export class AppNavItemComponent implements OnChanges {
|
||||
@Output() notify: EventEmitter<boolean> = new EventEmitter<boolean>();
|
||||
|
||||
@Input() item: NavItem | any;
|
||||
|
||||
expanded: any = false;
|
||||
|
||||
@HostBinding('attr.aria-expanded') ariaExpanded = this.expanded;
|
||||
@Input() depth: any;
|
||||
|
||||
constructor(public navService: NavService, public router: Router) {}
|
||||
|
||||
ngOnChanges() {
|
||||
const url = this.navService.currentUrl();
|
||||
if (this.item.route && url) {
|
||||
this.expanded = url.indexOf(`/${this.item.route}`) === 0;
|
||||
this.ariaExpanded = this.expanded;
|
||||
}
|
||||
}
|
||||
|
||||
onItemSelected(item: NavItem) {
|
||||
if (!item.children || !item.children.length) {
|
||||
this.router.navigate([item.route]);
|
||||
}
|
||||
if (item.children && item.children.length) {
|
||||
this.expanded = !this.expanded;
|
||||
}
|
||||
//scroll
|
||||
window.scroll({
|
||||
top: 0,
|
||||
left: 0,
|
||||
behavior: 'smooth',
|
||||
});
|
||||
if (!this.expanded) {
|
||||
if (window.innerWidth < 1024) {
|
||||
this.notify.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
openExternalLink(url: string): void {
|
||||
if (url) {
|
||||
window.open(url, '_blank');
|
||||
}
|
||||
}
|
||||
|
||||
onSubItemSelected(item: NavItem) {
|
||||
if (!item.children || !item.children.length) {
|
||||
if (this.expanded && window.innerWidth < 1024) {
|
||||
this.notify.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
export interface NavItem {
|
||||
displayName?: string;
|
||||
iconName?: string;
|
||||
navCap?: string;
|
||||
route?: string;
|
||||
children?: NavItem[];
|
||||
chip?: boolean;
|
||||
chipContent?: string;
|
||||
chipClass?: string;
|
||||
external?: boolean;
|
||||
export interface NavItem {
|
||||
displayName?: string;
|
||||
iconName?: string;
|
||||
navCap?: string;
|
||||
route?: string;
|
||||
children?: NavItem[];
|
||||
chip?: boolean;
|
||||
chipContent?: string;
|
||||
chipClass?: string;
|
||||
external?: boolean;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,10 @@
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<div class="branding"><app-branding></app-branding></div>
|
||||
|
||||
@if(showToggle) {
|
||||
<a href="javascript:void(0)" (click)="toggleMobileNav.emit()"
|
||||
class="d-flex justify-content-center ng-star-inserted icon-40 align-items-center">
|
||||
<i-tabler name="x" class="icon-20 d-flex"></i-tabler>
|
||||
</a>
|
||||
}
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<div class="branding"><app-branding></app-branding></div>
|
||||
|
||||
@if(showToggle) {
|
||||
<a href="javascript:void(0)" (click)="toggleMobileNav.emit()"
|
||||
class="d-flex justify-content-center ng-star-inserted icon-40 align-items-center">
|
||||
<i-tabler name="x" class="icon-20 d-flex"></i-tabler>
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
@@ -1,25 +1,25 @@
|
||||
import {
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnInit,
|
||||
Output,
|
||||
ViewChild,
|
||||
} from '@angular/core';
|
||||
import { BrandingComponent } from './branding.component';
|
||||
import { TablerIconsModule } from 'angular-tabler-icons';
|
||||
import { MaterialModule } from 'src/app/material.module';
|
||||
|
||||
@Component({
|
||||
selector: 'app-sidebar',
|
||||
imports: [BrandingComponent, TablerIconsModule, MaterialModule],
|
||||
templateUrl: './sidebar.component.html',
|
||||
})
|
||||
export class SidebarComponent implements OnInit {
|
||||
constructor() {}
|
||||
@Input() showToggle = true;
|
||||
@Output() toggleMobileNav = new EventEmitter<void>();
|
||||
@Output() toggleCollapsed = new EventEmitter<void>();
|
||||
|
||||
ngOnInit(): void {}
|
||||
}
|
||||
import {
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnInit,
|
||||
Output,
|
||||
ViewChild,
|
||||
} from '@angular/core';
|
||||
import { BrandingComponent } from './branding.component';
|
||||
import { TablerIconsModule } from 'angular-tabler-icons';
|
||||
import { MaterialModule } from 'src/app/material.module';
|
||||
|
||||
@Component({
|
||||
selector: 'app-sidebar',
|
||||
imports: [BrandingComponent, TablerIconsModule, MaterialModule],
|
||||
templateUrl: './sidebar.component.html',
|
||||
})
|
||||
export class SidebarComponent implements OnInit {
|
||||
constructor() {}
|
||||
@Input() showToggle = true;
|
||||
@Output() toggleMobileNav = new EventEmitter<void>();
|
||||
@Output() toggleCollapsed = new EventEmitter<void>();
|
||||
|
||||
ngOnInit(): void {}
|
||||
}
|
||||
|
||||
@@ -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="d-none d-sm-flex align-items-center justify-content-center gap-20">
|
||||
<a class="d-flex align-items-center" href="https://adminmart.com/" target="_blank">
|
||||
<img src="/assets/images/logos/logo-adminmart.svg" alt="" width="150">
|
||||
</a>
|
||||
|
||||
<div class="linkbar d-none d-lg-flex align-items-center justify-content-center gap-16">
|
||||
<!-- Templates -->
|
||||
<a mat-button class="link-hover p-x-0 text-white d-flex" href="https://adminmart.com/templates/angular/"
|
||||
target="_blank">
|
||||
<div class="d-flex align-items-center gap-8 f-s-16 f-w-400">
|
||||
<i class="iconify icon-20 d-flex" data-icon="solar:window-frame-linear"></i>
|
||||
Templates
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<!-- Support -->
|
||||
<a mat-button class="link-hover p-x-0 text-white d-flex" href="https://adminmart.com/support/"
|
||||
target="_blank">
|
||||
<div class="d-flex align-items-center gap-8 f-s-16 f-w-400">
|
||||
<i class="iconify icon-20 d-flex" data-icon="solar:question-circle-linear"></i>
|
||||
Help
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<!-- Hire Us -->
|
||||
<a mat-button class="link-hover p-x-0 text-white d-flex" href="https://adminmart.com/hire-us/"
|
||||
target="_blank">
|
||||
<div class="d-flex align-items-center gap-8 f-s-16 f-w-400">
|
||||
<i class="iconify icon-20 d-flex" data-icon="solar:case-round-linear"></i>
|
||||
Hire Us
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="topstrip-right d-flex align-items-center justify-content-center gap-16">
|
||||
<h6 class="text-linear-gradient f-s-14 text-uppercase text-lg-left text-center">Checkout Pro Version</h6>
|
||||
|
||||
<div class="topstrip-right-inner d-flex justify-content-center align-items-center gap-10">
|
||||
|
||||
<div class="d-flex justify-content-center align-items-center gap-10">
|
||||
<!-- Live Preview -->
|
||||
<button class="live-preview-drop d-flex align-items-center gap-4 text-white f-s-16 p-x-16" mat-button
|
||||
[matMenuTriggerFor]="beforeMenu">
|
||||
<div class="d-flex align-items-center gap-6">
|
||||
Live Preview
|
||||
<i class="iconify icon-20 d-flex" data-icon="solar:alt-arrow-down-linear"></i>
|
||||
</div>
|
||||
</button>
|
||||
<mat-menu class="p-x-16 p-y-8 rounded-7" #beforeMenu="matMenu" xPosition="before">
|
||||
<a mat-menu-item class="rounded-7"
|
||||
href="https://adminmart.com/product/modernize-angular-material-dashboard/?ref=56#product-demo-section"
|
||||
target="_blank">
|
||||
<div class="d-flex align-items-center gap-12 f-s-16">
|
||||
<img src="/assets/images/svgs/angular-cat-icon.svg" width="18" alt="angular">
|
||||
Angular Version
|
||||
</div>
|
||||
</a>
|
||||
<a mat-menu-item class="rounded-7"
|
||||
href="https://adminmart.com/product/modernize-react-mui-dashboard-theme/?ref=56#product-demo-section"
|
||||
target="_blank">
|
||||
<div class="d-flex align-items-center gap-12 f-s-16">
|
||||
<img src="/assets/images/svgs/react-cat-icon.svg" width="18" alt="react">
|
||||
React Version
|
||||
</div>
|
||||
</a>
|
||||
<a mat-menu-item class="rounded-7"
|
||||
href="https://adminmart.com/product/modernize-vuetify-vue-admin-dashboard/?ref=56#product-demo-section"
|
||||
target="_blank">
|
||||
<div class="d-flex align-items-center gap-12 f-s-16">
|
||||
<img src="/assets/images/svgs/vue-cat-icon.svg" width="18" alt="vueJs">
|
||||
VueJs Version
|
||||
</div>
|
||||
</a>
|
||||
<a mat-menu-item class="rounded-7"
|
||||
href="https://adminmart.com/product/modernize-next-js-admin-dashboard/?ref=56#product-demo-section"
|
||||
target="_blank">
|
||||
<div class="d-flex align-items-center gap-12 f-s-16">
|
||||
<img src="/assets/images/svgs/next-cat-icon.svg" width="18" alt="nextJs">
|
||||
NextJs Version
|
||||
</div>
|
||||
</a>
|
||||
<a mat-menu-item class="rounded-7"
|
||||
href="https://adminmart.com/product/modernize-nuxt-js-admin-dashboard/?ref=56#product-demo-section"
|
||||
target="_blank">
|
||||
<div class="d-flex align-items-center gap-12 f-s-16">
|
||||
<img src="/assets/images/svgs/nuxt-cat-icon.svg" width="18" alt="nuxtJs">
|
||||
NuxtJs Version
|
||||
</div>
|
||||
</a>
|
||||
<a mat-menu-item class="rounded-7"
|
||||
href="https://adminmart.com/product/modernize-tailwind-nextjs-dashboard-template/?ref=56#product-demo-section"
|
||||
target="_blank">
|
||||
<div class="d-flex align-items-center gap-12 f-s-16">
|
||||
<img src="/assets/images/svgs/tailwindcss.svg" width="20" alt="tailwind">
|
||||
Tailwind Version
|
||||
</div>
|
||||
</a>
|
||||
<a mat-menu-item class="rounded-7"
|
||||
href="https://adminmart.com/product/modernize-bootstrap-5-admin-template/?ref=56#product-demo-section"
|
||||
target="_blank">
|
||||
<div class="d-flex align-items-center gap-12 f-s-16">
|
||||
<img src="/assets/images/svgs/bt-cat-icon.svg" width="20" alt="bootstrap">
|
||||
Bootstrap Version
|
||||
</div>
|
||||
</a>
|
||||
</mat-menu>
|
||||
|
||||
<!-- Get Pro -->
|
||||
<a mat-button class="get-pro-btn text-white p-x-16"
|
||||
href="https://adminmart.com/product/modernize-angular-material-dashboard/?ref=56" target="_blank">
|
||||
<div class="d-flex align-items-center gap-8 f-s-16 f-w-400">
|
||||
<i class="iconify icon-18 d-flex" data-icon="solar:crown-linear"></i>
|
||||
Get Pro
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-topstrip bg-dark text-white p-y-16 p-x-24 w-100 d-flex align-items-center justify-content-between">
|
||||
<div class="d-none d-sm-flex align-items-center justify-content-center gap-20">
|
||||
<a class="d-flex align-items-center" href="https://adminmart.com/" target="_blank">
|
||||
<img src="/assets/images/logos/logo-adminmart.svg" alt="" width="150">
|
||||
</a>
|
||||
|
||||
<div class="linkbar d-none d-lg-flex align-items-center justify-content-center gap-16">
|
||||
<!-- Templates -->
|
||||
<a mat-button class="link-hover p-x-0 text-white d-flex" href="https://adminmart.com/templates/angular/"
|
||||
target="_blank">
|
||||
<div class="d-flex align-items-center gap-8 f-s-16 f-w-400">
|
||||
<i class="iconify icon-20 d-flex" data-icon="solar:window-frame-linear"></i>
|
||||
Templates
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<!-- Support -->
|
||||
<a mat-button class="link-hover p-x-0 text-white d-flex" href="https://adminmart.com/support/"
|
||||
target="_blank">
|
||||
<div class="d-flex align-items-center gap-8 f-s-16 f-w-400">
|
||||
<i class="iconify icon-20 d-flex" data-icon="solar:question-circle-linear"></i>
|
||||
Help
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<!-- Hire Us -->
|
||||
<a mat-button class="link-hover p-x-0 text-white d-flex" href="https://adminmart.com/hire-us/"
|
||||
target="_blank">
|
||||
<div class="d-flex align-items-center gap-8 f-s-16 f-w-400">
|
||||
<i class="iconify icon-20 d-flex" data-icon="solar:case-round-linear"></i>
|
||||
Hire Us
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="topstrip-right d-flex align-items-center justify-content-center gap-16">
|
||||
<h6 class="text-linear-gradient f-s-14 text-uppercase text-lg-left text-center">Checkout Pro Version</h6>
|
||||
|
||||
<div class="topstrip-right-inner d-flex justify-content-center align-items-center gap-10">
|
||||
|
||||
<div class="d-flex justify-content-center align-items-center gap-10">
|
||||
<!-- Live Preview -->
|
||||
<button class="live-preview-drop d-flex align-items-center gap-4 text-white f-s-16 p-x-16" mat-button
|
||||
[matMenuTriggerFor]="beforeMenu">
|
||||
<div class="d-flex align-items-center gap-6">
|
||||
Live Preview
|
||||
<i class="iconify icon-20 d-flex" data-icon="solar:alt-arrow-down-linear"></i>
|
||||
</div>
|
||||
</button>
|
||||
<mat-menu class="p-x-16 p-y-8 rounded-7" #beforeMenu="matMenu" xPosition="before">
|
||||
<a mat-menu-item class="rounded-7"
|
||||
href="https://adminmart.com/product/modernize-angular-material-dashboard/?ref=56#product-demo-section"
|
||||
target="_blank">
|
||||
<div class="d-flex align-items-center gap-12 f-s-16">
|
||||
<img src="/assets/images/svgs/angular-cat-icon.svg" width="18" alt="angular">
|
||||
Angular Version
|
||||
</div>
|
||||
</a>
|
||||
<a mat-menu-item class="rounded-7"
|
||||
href="https://adminmart.com/product/modernize-react-mui-dashboard-theme/?ref=56#product-demo-section"
|
||||
target="_blank">
|
||||
<div class="d-flex align-items-center gap-12 f-s-16">
|
||||
<img src="/assets/images/svgs/react-cat-icon.svg" width="18" alt="react">
|
||||
React Version
|
||||
</div>
|
||||
</a>
|
||||
<a mat-menu-item class="rounded-7"
|
||||
href="https://adminmart.com/product/modernize-vuetify-vue-admin-dashboard/?ref=56#product-demo-section"
|
||||
target="_blank">
|
||||
<div class="d-flex align-items-center gap-12 f-s-16">
|
||||
<img src="/assets/images/svgs/vue-cat-icon.svg" width="18" alt="vueJs">
|
||||
VueJs Version
|
||||
</div>
|
||||
</a>
|
||||
<a mat-menu-item class="rounded-7"
|
||||
href="https://adminmart.com/product/modernize-next-js-admin-dashboard/?ref=56#product-demo-section"
|
||||
target="_blank">
|
||||
<div class="d-flex align-items-center gap-12 f-s-16">
|
||||
<img src="/assets/images/svgs/next-cat-icon.svg" width="18" alt="nextJs">
|
||||
NextJs Version
|
||||
</div>
|
||||
</a>
|
||||
<a mat-menu-item class="rounded-7"
|
||||
href="https://adminmart.com/product/modernize-nuxt-js-admin-dashboard/?ref=56#product-demo-section"
|
||||
target="_blank">
|
||||
<div class="d-flex align-items-center gap-12 f-s-16">
|
||||
<img src="/assets/images/svgs/nuxt-cat-icon.svg" width="18" alt="nuxtJs">
|
||||
NuxtJs Version
|
||||
</div>
|
||||
</a>
|
||||
<a mat-menu-item class="rounded-7"
|
||||
href="https://adminmart.com/product/modernize-tailwind-nextjs-dashboard-template/?ref=56#product-demo-section"
|
||||
target="_blank">
|
||||
<div class="d-flex align-items-center gap-12 f-s-16">
|
||||
<img src="/assets/images/svgs/tailwindcss.svg" width="20" alt="tailwind">
|
||||
Tailwind Version
|
||||
</div>
|
||||
</a>
|
||||
<a mat-menu-item class="rounded-7"
|
||||
href="https://adminmart.com/product/modernize-bootstrap-5-admin-template/?ref=56#product-demo-section"
|
||||
target="_blank">
|
||||
<div class="d-flex align-items-center gap-12 f-s-16">
|
||||
<img src="/assets/images/svgs/bt-cat-icon.svg" width="20" alt="bootstrap">
|
||||
Bootstrap Version
|
||||
</div>
|
||||
</a>
|
||||
</mat-menu>
|
||||
|
||||
<!-- Get Pro -->
|
||||
<a mat-button class="get-pro-btn text-white p-x-16"
|
||||
href="https://adminmart.com/product/modernize-angular-material-dashboard/?ref=56" target="_blank">
|
||||
<div class="d-flex align-items-center gap-8 f-s-16 f-w-400">
|
||||
<i class="iconify icon-18 d-flex" data-icon="solar:crown-linear"></i>
|
||||
Get Pro
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,15 +1,15 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { TablerIconsModule } from 'angular-tabler-icons';
|
||||
|
||||
@Component({
|
||||
selector: 'app-topstrip',
|
||||
imports: [TablerIconsModule, MatButtonModule, MatMenuModule],
|
||||
templateUrl: './topstrip.component.html',
|
||||
})
|
||||
export class AppTopstripComponent {
|
||||
constructor() { }
|
||||
|
||||
}
|
||||
import { Component } from '@angular/core';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { TablerIconsModule } from 'angular-tabler-icons';
|
||||
|
||||
@Component({
|
||||
selector: 'app-topstrip',
|
||||
imports: [TablerIconsModule, MatButtonModule, MatMenuModule],
|
||||
templateUrl: './topstrip.component.html',
|
||||
})
|
||||
export class AppTopstripComponent {
|
||||
constructor() { }
|
||||
|
||||
}
|
||||
|
||||
@@ -1,85 +1,85 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
// Material Form Controls
|
||||
import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatRadioModule } from '@angular/material/radio';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatSliderModule } from '@angular/material/slider';
|
||||
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||
// Material Navigation
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { MatSidenavModule } from '@angular/material/sidenav';
|
||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
// Material Layout
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatExpansionModule } from '@angular/material/expansion';
|
||||
import { MatGridListModule } from '@angular/material/grid-list';
|
||||
import { MatListModule } from '@angular/material/list';
|
||||
import { MatStepperModule } from '@angular/material/stepper';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
import { MatTreeModule } from '@angular/material/tree';
|
||||
// Material Buttons & Indicators
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
||||
import { MatBadgeModule } from '@angular/material/badge';
|
||||
import { MatChipsModule } from '@angular/material/chips';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||
import { MatRippleModule } from '@angular/material/core';
|
||||
// Material Popups & Modals
|
||||
import { MatBottomSheetModule } from '@angular/material/bottom-sheet';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
// Material Data tables
|
||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||
import { MatSortModule } from '@angular/material/sort';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
|
||||
@NgModule({
|
||||
declarations: [],
|
||||
exports: [
|
||||
MatAutocompleteModule,
|
||||
MatCheckboxModule,
|
||||
MatDatepickerModule,
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
MatRadioModule,
|
||||
MatSelectModule,
|
||||
MatSliderModule,
|
||||
MatSlideToggleModule,
|
||||
MatMenuModule,
|
||||
MatSidenavModule,
|
||||
MatToolbarModule,
|
||||
MatCardModule,
|
||||
MatDividerModule,
|
||||
MatExpansionModule,
|
||||
MatGridListModule,
|
||||
MatListModule,
|
||||
MatStepperModule,
|
||||
MatTabsModule,
|
||||
MatTreeModule,
|
||||
MatButtonModule,
|
||||
MatButtonToggleModule,
|
||||
MatBadgeModule,
|
||||
MatChipsModule,
|
||||
MatIconModule,
|
||||
MatProgressSpinnerModule,
|
||||
MatProgressBarModule,
|
||||
MatRippleModule,
|
||||
MatBottomSheetModule,
|
||||
MatDialogModule,
|
||||
MatSnackBarModule,
|
||||
MatTooltipModule,
|
||||
MatPaginatorModule,
|
||||
MatSortModule,
|
||||
MatTableModule,
|
||||
],
|
||||
})
|
||||
export class MaterialModule {}
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
// Material Form Controls
|
||||
import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatRadioModule } from '@angular/material/radio';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatSliderModule } from '@angular/material/slider';
|
||||
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||
// Material Navigation
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { MatSidenavModule } from '@angular/material/sidenav';
|
||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
// Material Layout
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatExpansionModule } from '@angular/material/expansion';
|
||||
import { MatGridListModule } from '@angular/material/grid-list';
|
||||
import { MatListModule } from '@angular/material/list';
|
||||
import { MatStepperModule } from '@angular/material/stepper';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
import { MatTreeModule } from '@angular/material/tree';
|
||||
// Material Buttons & Indicators
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
||||
import { MatBadgeModule } from '@angular/material/badge';
|
||||
import { MatChipsModule } from '@angular/material/chips';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||
import { MatRippleModule } from '@angular/material/core';
|
||||
// Material Popups & Modals
|
||||
import { MatBottomSheetModule } from '@angular/material/bottom-sheet';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
// Material Data tables
|
||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||
import { MatSortModule } from '@angular/material/sort';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
|
||||
@NgModule({
|
||||
declarations: [],
|
||||
exports: [
|
||||
MatAutocompleteModule,
|
||||
MatCheckboxModule,
|
||||
MatDatepickerModule,
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
MatRadioModule,
|
||||
MatSelectModule,
|
||||
MatSliderModule,
|
||||
MatSlideToggleModule,
|
||||
MatMenuModule,
|
||||
MatSidenavModule,
|
||||
MatToolbarModule,
|
||||
MatCardModule,
|
||||
MatDividerModule,
|
||||
MatExpansionModule,
|
||||
MatGridListModule,
|
||||
MatListModule,
|
||||
MatStepperModule,
|
||||
MatTabsModule,
|
||||
MatTreeModule,
|
||||
MatButtonModule,
|
||||
MatButtonToggleModule,
|
||||
MatBadgeModule,
|
||||
MatChipsModule,
|
||||
MatIconModule,
|
||||
MatProgressSpinnerModule,
|
||||
MatProgressBarModule,
|
||||
MatRippleModule,
|
||||
MatBottomSheetModule,
|
||||
MatDialogModule,
|
||||
MatSnackBarModule,
|
||||
MatTooltipModule,
|
||||
MatPaginatorModule,
|
||||
MatSortModule,
|
||||
MatTableModule,
|
||||
],
|
||||
})
|
||||
export class MaterialModule {}
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import { Routes } from '@angular/router';
|
||||
|
||||
import { AppSideLoginComponent } from './side-login/side-login.component';
|
||||
import { AppSideRegisterComponent } from './side-register/side-register.component';
|
||||
|
||||
export const AuthenticationRoutes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
children: [
|
||||
{
|
||||
path: 'login',
|
||||
component: AppSideLoginComponent,
|
||||
},
|
||||
{
|
||||
path: 'register',
|
||||
component: AppSideRegisterComponent,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
import { Routes } from '@angular/router';
|
||||
|
||||
import { AppSideLoginComponent } from './side-login/side-login.component';
|
||||
import { AppSideRegisterComponent } from './side-register/side-register.component';
|
||||
|
||||
export const AuthenticationRoutes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
children: [
|
||||
{
|
||||
path: 'login',
|
||||
component: AppSideLoginComponent,
|
||||
},
|
||||
{
|
||||
path: 'register',
|
||||
component: AppSideRegisterComponent,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,64 +1,64 @@
|
||||
<div class="blank-layout-container justify-content-center align-items-center bg-light">
|
||||
<div class="position-relative row w-100 h-100 bg-gredient justify-content-center">
|
||||
<div class="col-lg-4 d-flex align-items-center">
|
||||
<mat-card class="cardWithShadow boxed-auth">
|
||||
<mat-card-content class="p-32">
|
||||
<div class="text-center">
|
||||
<a [routerLink]="['/dashboard']">
|
||||
<img src="./assets/images/logos/dark-logo.svg" class="align-middle m-2" alt="logo" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="row m-t-24 custom-row">
|
||||
<div class="col-12 col-sm-6">
|
||||
<button mat-stroked-button class="w-100">
|
||||
<div class="d-flex align-items-center">
|
||||
<img src="/assets/images/svgs/google-icon.svg" alt="google" width="16" class="m-r-8" />
|
||||
<span>
|
||||
Sign in with Google
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<button mat-stroked-button class="w-100 d-flex align-items-center">
|
||||
<div class="d-flex align-items-center">
|
||||
<img src="/assets/images/svgs/facebook-icon.svg" alt="facebook" width="40" class="m-r-4" />
|
||||
Sign in with FB
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="or-border m-t-30">or sign in with</div>
|
||||
|
||||
<form class="m-t-30">
|
||||
<mat-label class="f-s-14 f-w-600 m-b-12 d-block">Username</mat-label>
|
||||
<mat-form-field appearance="outline" class="w-100" color="primary">
|
||||
<input matInput />
|
||||
</mat-form-field>
|
||||
<!-- password -->
|
||||
<mat-label class="f-s-14 f-w-600 m-b-12 d-block">Password</mat-label>
|
||||
<mat-form-field appearance="outline" class="w-100" color="primary">
|
||||
<input matInput type="password" />
|
||||
</mat-form-field>
|
||||
|
||||
<div class="d-flex align-items-center m-b-12">
|
||||
<mat-checkbox color="primary">Remember this Device</mat-checkbox>
|
||||
<a [routerLink]="['/']" class="text-primary f-w-600 text-decoration-none m-l-auto f-s-14">Forgot Password
|
||||
?</a>
|
||||
</div>
|
||||
<a [routerLink]="['/']" mat-flat-button color="primary" class="w-100">
|
||||
Sign In
|
||||
</a>
|
||||
<!-- input -->
|
||||
</form>
|
||||
<span class="d-block f-w-500 text-center m-t-24">New to Modernize?
|
||||
<a [routerLink]="['/authentication/register']" class="text-decoration-none text-primary f-w-500 f-s-14">
|
||||
Create an account</a>
|
||||
</span>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div>
|
||||
<div class="blank-layout-container justify-content-center align-items-center bg-light">
|
||||
<div class="position-relative row w-100 h-100 bg-gredient justify-content-center">
|
||||
<div class="col-lg-4 d-flex align-items-center">
|
||||
<mat-card class="cardWithShadow boxed-auth">
|
||||
<mat-card-content class="p-32">
|
||||
<div class="text-center">
|
||||
<a [routerLink]="['/dashboard']">
|
||||
<img src="./assets/images/logos/dark-logo.svg" class="align-middle m-2" alt="logo" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="row m-t-24 custom-row">
|
||||
<div class="col-12 col-sm-6">
|
||||
<button mat-stroked-button class="w-100">
|
||||
<div class="d-flex align-items-center">
|
||||
<img src="/assets/images/svgs/google-icon.svg" alt="google" width="16" class="m-r-8" />
|
||||
<span>
|
||||
Sign in with Google
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<button mat-stroked-button class="w-100 d-flex align-items-center">
|
||||
<div class="d-flex align-items-center">
|
||||
<img src="/assets/images/svgs/facebook-icon.svg" alt="facebook" width="40" class="m-r-4" />
|
||||
Sign in with FB
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="or-border m-t-30">or sign in with</div>
|
||||
|
||||
<form class="m-t-30">
|
||||
<mat-label class="f-s-14 f-w-600 m-b-12 d-block">Username</mat-label>
|
||||
<mat-form-field appearance="outline" class="w-100" color="primary">
|
||||
<input matInput />
|
||||
</mat-form-field>
|
||||
<!-- password -->
|
||||
<mat-label class="f-s-14 f-w-600 m-b-12 d-block">Password</mat-label>
|
||||
<mat-form-field appearance="outline" class="w-100" color="primary">
|
||||
<input matInput type="password" />
|
||||
</mat-form-field>
|
||||
|
||||
<div class="d-flex align-items-center m-b-12">
|
||||
<mat-checkbox color="primary">Remember this Device</mat-checkbox>
|
||||
<a [routerLink]="['/']" class="text-primary f-w-600 text-decoration-none m-l-auto f-s-14">Forgot Password
|
||||
?</a>
|
||||
</div>
|
||||
<a [routerLink]="['/']" mat-flat-button color="primary" class="w-100">
|
||||
Sign In
|
||||
</a>
|
||||
<!-- input -->
|
||||
</form>
|
||||
<span class="d-block f-w-500 text-center m-t-24">New to Modernize?
|
||||
<a [routerLink]="['/authentication/register']" class="text-decoration-none text-primary f-w-500 f-s-14">
|
||||
Create an account</a>
|
||||
</span>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,31 +1,31 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { FormGroup, FormControl, Validators } from '@angular/forms';
|
||||
import { Router } from '@angular/router';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { MaterialModule } from 'src/app/material.module';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'app-side-login',
|
||||
imports: [RouterModule, MaterialModule, FormsModule, ReactiveFormsModule],
|
||||
templateUrl: './side-login.component.html',
|
||||
})
|
||||
export class AppSideLoginComponent {
|
||||
|
||||
constructor( private router: Router) {}
|
||||
|
||||
form = new FormGroup({
|
||||
uname: new FormControl('', [Validators.required, Validators.minLength(6)]),
|
||||
password: new FormControl('', [Validators.required]),
|
||||
});
|
||||
|
||||
get f() {
|
||||
return this.form.controls;
|
||||
}
|
||||
|
||||
submit() {
|
||||
// console.log(this.form.value);
|
||||
this.router.navigate(['/']);
|
||||
}
|
||||
}
|
||||
import { Component } from '@angular/core';
|
||||
import { FormGroup, FormControl, Validators } from '@angular/forms';
|
||||
import { Router } from '@angular/router';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { MaterialModule } from 'src/app/material.module';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'app-side-login',
|
||||
imports: [RouterModule, MaterialModule, FormsModule, ReactiveFormsModule],
|
||||
templateUrl: './side-login.component.html',
|
||||
})
|
||||
export class AppSideLoginComponent {
|
||||
|
||||
constructor( private router: Router) {}
|
||||
|
||||
form = new FormGroup({
|
||||
uname: new FormControl('', [Validators.required, Validators.minLength(6)]),
|
||||
password: new FormControl('', [Validators.required]),
|
||||
});
|
||||
|
||||
get f() {
|
||||
return this.form.controls;
|
||||
}
|
||||
|
||||
submit() {
|
||||
// console.log(this.form.value);
|
||||
this.router.navigate(['/']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,62 +1,62 @@
|
||||
<div class="blank-layout-container justify-content-center align-items-center bg-light">
|
||||
<div class="position-relative row w-100 h-100 bg-gredient justify-content-center">
|
||||
<div class="col-lg-4 d-flex align-items-center">
|
||||
<mat-card class="cardWithShadow boxed-auth">
|
||||
<mat-card-content class="p-32">
|
||||
<div class="text-center">
|
||||
<a [routerLink]="['/dashboard']">
|
||||
<img src="./assets/images/logos/dark-logo.svg" class="align-middle m-2" alt="logo" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="row m-t-24 custom-row">
|
||||
<div class="col-12 col-sm-6">
|
||||
<button mat-stroked-button class="w-100">
|
||||
<div class="d-flex align-items-center">
|
||||
<img src="/assets/images/svgs/google-icon.svg" alt="google" width="16" class="m-r-8" />
|
||||
Sign in with Google
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<button mat-stroked-button class="w-100 d-flex align-items-center">
|
||||
<div class="d-flex align-items-center">
|
||||
<img src="/assets/images/svgs/facebook-icon.svg" alt="facebook" width="40" class="m-r-4" />
|
||||
Sign in with FB
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="or-border m-t-30">or sign up with</div>
|
||||
|
||||
<form class="m-t-30">
|
||||
<mat-label class="f-s-14 f-w-600 m-b-12 d-block">Name</mat-label>
|
||||
<mat-form-field appearance="outline" class="w-100" color="primary">
|
||||
<input matInput />
|
||||
</mat-form-field>
|
||||
<mat-label class="f-s-14 f-w-600 m-b-12 d-block">Email Adddress</mat-label>
|
||||
<mat-form-field appearance="outline" class="w-100" color="primary">
|
||||
<input matInput type="email" />
|
||||
</mat-form-field>
|
||||
<!-- password -->
|
||||
<mat-label class="f-s-14 f-w-600 m-b-12 d-block">Password</mat-label>
|
||||
<mat-form-field appearance="outline" class="w-100" color="primary">
|
||||
<input matInput type="password" />
|
||||
</mat-form-field>
|
||||
|
||||
<a [routerLink]="['/']" mat-flat-button color="primary" class="w-100">
|
||||
Sign Up
|
||||
</a>
|
||||
<!-- input -->
|
||||
</form>
|
||||
<span class="d-block f-w-500 text-center m-t-24">Already have an Account?
|
||||
|
||||
<a [routerLink]="['/authentication/login']" class="text-decoration-none text-primary f-w-500 f-s-14">
|
||||
Sign In</a>
|
||||
</span>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div>
|
||||
<div class="blank-layout-container justify-content-center align-items-center bg-light">
|
||||
<div class="position-relative row w-100 h-100 bg-gredient justify-content-center">
|
||||
<div class="col-lg-4 d-flex align-items-center">
|
||||
<mat-card class="cardWithShadow boxed-auth">
|
||||
<mat-card-content class="p-32">
|
||||
<div class="text-center">
|
||||
<a [routerLink]="['/dashboard']">
|
||||
<img src="./assets/images/logos/dark-logo.svg" class="align-middle m-2" alt="logo" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="row m-t-24 custom-row">
|
||||
<div class="col-12 col-sm-6">
|
||||
<button mat-stroked-button class="w-100">
|
||||
<div class="d-flex align-items-center">
|
||||
<img src="/assets/images/svgs/google-icon.svg" alt="google" width="16" class="m-r-8" />
|
||||
Sign in with Google
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-12 col-sm-6">
|
||||
<button mat-stroked-button class="w-100 d-flex align-items-center">
|
||||
<div class="d-flex align-items-center">
|
||||
<img src="/assets/images/svgs/facebook-icon.svg" alt="facebook" width="40" class="m-r-4" />
|
||||
Sign in with FB
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="or-border m-t-30">or sign up with</div>
|
||||
|
||||
<form class="m-t-30">
|
||||
<mat-label class="f-s-14 f-w-600 m-b-12 d-block">Name</mat-label>
|
||||
<mat-form-field appearance="outline" class="w-100" color="primary">
|
||||
<input matInput />
|
||||
</mat-form-field>
|
||||
<mat-label class="f-s-14 f-w-600 m-b-12 d-block">Email Adddress</mat-label>
|
||||
<mat-form-field appearance="outline" class="w-100" color="primary">
|
||||
<input matInput type="email" />
|
||||
</mat-form-field>
|
||||
<!-- password -->
|
||||
<mat-label class="f-s-14 f-w-600 m-b-12 d-block">Password</mat-label>
|
||||
<mat-form-field appearance="outline" class="w-100" color="primary">
|
||||
<input matInput type="password" />
|
||||
</mat-form-field>
|
||||
|
||||
<a [routerLink]="['/']" mat-flat-button color="primary" class="w-100">
|
||||
Sign Up
|
||||
</a>
|
||||
<!-- input -->
|
||||
</form>
|
||||
<span class="d-block f-w-500 text-center m-t-24">Already have an Account?
|
||||
|
||||
<a [routerLink]="['/authentication/login']" class="text-decoration-none text-primary f-w-500 f-s-14">
|
||||
Sign In</a>
|
||||
</span>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,33 +1,33 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { CoreService } from 'src/app/services/core.service';
|
||||
import { FormGroup, FormControl, Validators } from '@angular/forms';
|
||||
import { Router } from '@angular/router';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { MaterialModule } from 'src/app/material.module';
|
||||
|
||||
@Component({
|
||||
selector: 'app-side-register',
|
||||
imports: [RouterModule, MaterialModule, FormsModule, ReactiveFormsModule],
|
||||
templateUrl: './side-register.component.html',
|
||||
})
|
||||
export class AppSideRegisterComponent {
|
||||
options = this.settings.getOptions();
|
||||
|
||||
constructor(private settings: CoreService, private router: Router) {}
|
||||
|
||||
form = new FormGroup({
|
||||
uname: new FormControl('', [Validators.required, Validators.minLength(6)]),
|
||||
email: new FormControl('', [Validators.required]),
|
||||
password: new FormControl('', [Validators.required]),
|
||||
});
|
||||
|
||||
get f() {
|
||||
return this.form.controls;
|
||||
}
|
||||
|
||||
submit() {
|
||||
// console.log(this.form.value);
|
||||
this.router.navigate(['/']);
|
||||
}
|
||||
}
|
||||
import { Component } from '@angular/core';
|
||||
import { CoreService } from 'src/app/services/core.service';
|
||||
import { FormGroup, FormControl, Validators } from '@angular/forms';
|
||||
import { Router } from '@angular/router';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { MaterialModule } from 'src/app/material.module';
|
||||
|
||||
@Component({
|
||||
selector: 'app-side-register',
|
||||
imports: [RouterModule, MaterialModule, FormsModule, ReactiveFormsModule],
|
||||
templateUrl: './side-register.component.html',
|
||||
})
|
||||
export class AppSideRegisterComponent {
|
||||
options = this.settings.getOptions();
|
||||
|
||||
constructor(private settings: CoreService, private router: Router) {}
|
||||
|
||||
form = new FormGroup({
|
||||
uname: new FormControl('', [Validators.required, Validators.minLength(6)]),
|
||||
email: new FormControl('', [Validators.required]),
|
||||
password: new FormControl('', [Validators.required]),
|
||||
});
|
||||
|
||||
get f() {
|
||||
return this.form.controls;
|
||||
}
|
||||
|
||||
submit() {
|
||||
// console.log(this.form.value);
|
||||
this.router.navigate(['/']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import { Routes } from '@angular/router';
|
||||
|
||||
|
||||
// pages
|
||||
import { AppIconsComponent } from './icons/icons.component';
|
||||
import { AppSamplePageComponent } from './sample-page/sample-page.component';
|
||||
|
||||
export const ExtraRoutes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
children: [
|
||||
{
|
||||
path: 'icons',
|
||||
component: AppIconsComponent,
|
||||
},
|
||||
{
|
||||
path: 'sample-page',
|
||||
component: AppSamplePageComponent,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
import { Routes } from '@angular/router';
|
||||
|
||||
|
||||
// pages
|
||||
import { AppIconsComponent } from './icons/icons.component';
|
||||
import { AppSamplePageComponent } from './sample-page/sample-page.component';
|
||||
|
||||
export const ExtraRoutes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
children: [
|
||||
{
|
||||
path: 'icons',
|
||||
component: AppIconsComponent,
|
||||
},
|
||||
{
|
||||
path: 'sample-page',
|
||||
component: AppSamplePageComponent,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<!-- ============================================================== -->
|
||||
<!-- Simple four boxes Row -->
|
||||
<!-- ============================================================== -->
|
||||
<mat-card class="cardWithShadow">
|
||||
<mat-card-content>
|
||||
<mat-card-title>Icons</mat-card-title>
|
||||
<mat-card-subtitle class="m-b-24">Tabler Icons</mat-card-subtitle>
|
||||
<iframe src="https://tabler.io/icons" title="Tabler Icons" width="100%" height="630px"
|
||||
allowfullscreen frameBorder="0">
|
||||
</iframe>
|
||||
</mat-card-content>
|
||||
<!-- ============================================================== -->
|
||||
<!-- Simple four boxes Row -->
|
||||
<!-- ============================================================== -->
|
||||
<mat-card class="cardWithShadow">
|
||||
<mat-card-content>
|
||||
<mat-card-title>Icons</mat-card-title>
|
||||
<mat-card-subtitle class="m-b-24">Tabler Icons</mat-card-subtitle>
|
||||
<iframe src="https://tabler.io/icons" title="Tabler Icons" width="100%" height="630px"
|
||||
allowfullscreen frameBorder="0">
|
||||
</iframe>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { MaterialModule } from '../../../material.module';
|
||||
|
||||
@Component({
|
||||
selector: 'app-icons',
|
||||
imports: [MaterialModule],
|
||||
templateUrl: './icons.component.html',
|
||||
})
|
||||
export class AppIconsComponent { }
|
||||
import { Component } from '@angular/core';
|
||||
import { MaterialModule } from '../../../material.module';
|
||||
|
||||
@Component({
|
||||
selector: 'app-icons',
|
||||
imports: [MaterialModule],
|
||||
templateUrl: './icons.component.html',
|
||||
})
|
||||
export class AppIconsComponent { }
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<!-- ============================================================== -->
|
||||
<!-- Simple four boxes Row -->
|
||||
<!-- ============================================================== -->
|
||||
<mat-card class="cardWithShadow">
|
||||
<mat-card-content>
|
||||
<mat-card-title>Sample Page</mat-card-title>
|
||||
<mat-card-subtitle>This is test page</mat-card-subtitle>
|
||||
</mat-card-content>
|
||||
<!-- ============================================================== -->
|
||||
<!-- Simple four boxes Row -->
|
||||
<!-- ============================================================== -->
|
||||
<mat-card class="cardWithShadow">
|
||||
<mat-card-content>
|
||||
<mat-card-title>Sample Page</mat-card-title>
|
||||
<mat-card-subtitle>This is test page</mat-card-subtitle>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user