generated from flo/template-frontend
Initial commit
This commit is contained in:
commit
12ac40a875
27
README.md
Normal file
27
README.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# template
|
||||||
|
|
||||||
|
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 15.2.6.
|
||||||
|
|
||||||
|
## Development server
|
||||||
|
|
||||||
|
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.
|
||||||
|
|
||||||
|
## Code scaffolding
|
||||||
|
|
||||||
|
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
|
||||||
|
|
||||||
|
## Running unit tests
|
||||||
|
|
||||||
|
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||||
|
|
||||||
|
## Running end-to-end tests
|
||||||
|
|
||||||
|
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
|
||||||
|
|
||||||
|
## Further help
|
||||||
|
|
||||||
|
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
|
||||||
125
angular.json
Normal file
125
angular.json
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
{
|
||||||
|
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||||
|
"version": 1,
|
||||||
|
"newProjectRoot": "projects",
|
||||||
|
"projects": {
|
||||||
|
"template": {
|
||||||
|
"projectType": "application",
|
||||||
|
"schematics": {
|
||||||
|
"@schematics/angular:component": {
|
||||||
|
"style": "scss",
|
||||||
|
"skipTests": true
|
||||||
|
},
|
||||||
|
"@schematics/angular:class": {
|
||||||
|
"skipTests": true
|
||||||
|
},
|
||||||
|
"@schematics/angular:directive": {
|
||||||
|
"skipTests": true
|
||||||
|
},
|
||||||
|
"@schematics/angular:guard": {
|
||||||
|
"skipTests": true
|
||||||
|
},
|
||||||
|
"@schematics/angular:module": {
|
||||||
|
},
|
||||||
|
"@schematics/angular:pipe": {
|
||||||
|
"skipTests": true
|
||||||
|
},
|
||||||
|
"@schematics/angular:service": {
|
||||||
|
"skipTests": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "",
|
||||||
|
"sourceRoot": "src",
|
||||||
|
"prefix": "app",
|
||||||
|
"architect": {
|
||||||
|
"build": {
|
||||||
|
"builder": "@angular-devkit/build-angular:browser",
|
||||||
|
"options": {
|
||||||
|
"outputPath": "dist",
|
||||||
|
"index": "src/index.html",
|
||||||
|
"main": "src/main.ts",
|
||||||
|
"polyfills": [
|
||||||
|
"zone.js"
|
||||||
|
],
|
||||||
|
"tsConfig": "tsconfig.app.json",
|
||||||
|
"assets": [
|
||||||
|
"src/assets",
|
||||||
|
"src/favicon.ico"
|
||||||
|
],
|
||||||
|
"styles": [
|
||||||
|
"@angular/material/prebuilt-themes/deeppurple-amber.css",
|
||||||
|
"src/styles.scss"
|
||||||
|
],
|
||||||
|
"scripts": []
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"budgets": [
|
||||||
|
{
|
||||||
|
"type": "initial",
|
||||||
|
"maximumWarning": "800kb",
|
||||||
|
"maximumError": "2mb"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "anyComponentStyle",
|
||||||
|
"maximumWarning": "2kb",
|
||||||
|
"maximumError": "4kb"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"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": {
|
||||||
|
"browserTarget": "template:build:production"
|
||||||
|
},
|
||||||
|
"development": {
|
||||||
|
"browserTarget": "template:build:development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defaultConfiguration": "development"
|
||||||
|
},
|
||||||
|
"extract-i18n": {
|
||||||
|
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||||
|
"options": {
|
||||||
|
"browserTarget": "template:build"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
|
"options": {
|
||||||
|
"polyfills": [
|
||||||
|
"zone.js",
|
||||||
|
"zone.js/testing"
|
||||||
|
],
|
||||||
|
"tsConfig": "tsconfig.spec.json",
|
||||||
|
"assets": [
|
||||||
|
"src/assets",
|
||||||
|
"src/favicon.ico"
|
||||||
|
],
|
||||||
|
"styles": [
|
||||||
|
"@angular/material/prebuilt-themes/deeppurple-amber.scss",
|
||||||
|
"src/styles.scss"
|
||||||
|
],
|
||||||
|
"scripts": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cli": {
|
||||||
|
"analytics": false
|
||||||
|
}
|
||||||
|
}
|
||||||
43
bin/script/init
Executable file
43
bin/script/init
Executable file
@ -0,0 +1,43 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||||
|
PROJECT_DIR=$(realpath $SCRIPT_DIR/../../)
|
||||||
|
ENV_DIR=$(realpath $PROJECT_DIR/../../../)
|
||||||
|
|
||||||
|
EXIT=0
|
||||||
|
|
||||||
|
# Check docker-compose.yml file
|
||||||
|
if [ ! -f "$PROJECT_DIR/docker/docker-compose.yml" ]
|
||||||
|
then
|
||||||
|
cp "$PROJECT_DIR/docker/docker-compose.yml.dist" "$PROJECT_DIR/docker/docker-compose.yml"
|
||||||
|
EXIT=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check docker-compose-mac.yml file
|
||||||
|
if [ ! -f "$PROJECT_DIR/docker/docker-compose-mac.yml" ]
|
||||||
|
then
|
||||||
|
cp "$PROJECT_DIR/docker/docker-compose-mac.yml.dist" "$PROJECT_DIR/docker/docker-compose-mac.yml"
|
||||||
|
EXIT=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
if [ $EXIT -eq 1 ]
|
||||||
|
then
|
||||||
|
echo "docker-compose or env files created, please change variables and call init again"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Source key-scripts
|
||||||
|
source $ENV_DIR/bin/drun
|
||||||
|
source $ENV_DIR/bin/dexec
|
||||||
|
|
||||||
|
# Build and start docker containers
|
||||||
|
dexec template-frontend build
|
||||||
|
dexec template-frontend up -d
|
||||||
|
|
||||||
|
# Install node Packages
|
||||||
|
drun template-frontend npm install
|
||||||
|
drun template-frontend npm install -g @angular/cli
|
||||||
|
|
||||||
|
# Initial build of website
|
||||||
|
drun template-frontend npm run build
|
||||||
31
docker/docker-compose-mac.yml.dist
Normal file
31
docker/docker-compose-mac.yml.dist
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
networks:
|
||||||
|
template:
|
||||||
|
external: true
|
||||||
|
|
||||||
|
services:
|
||||||
|
template-frontend-app:
|
||||||
|
image: template-frontend-app
|
||||||
|
networks:
|
||||||
|
- template
|
||||||
|
volumes:
|
||||||
|
- /Users/flo/dev/frontend/template/:/var/www/
|
||||||
|
build:
|
||||||
|
context: ./../
|
||||||
|
dockerfile: ./docker/npm/dockerfile
|
||||||
|
tty: true
|
||||||
|
|
||||||
|
template-frontend-nginx:
|
||||||
|
image: template-frontend-nginx
|
||||||
|
networks:
|
||||||
|
- template
|
||||||
|
volumes:
|
||||||
|
- /Users/flo/dev/frontend/template/:/var/www/html:z
|
||||||
|
build:
|
||||||
|
context: ./../
|
||||||
|
dockerfile: ./docker/nginx/dockerfile
|
||||||
|
labels:
|
||||||
|
- "traefik.http.routers.frontend.rule=Host(`template.local`)"
|
||||||
|
- "traefik.http.routers.frontend.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.frontend.tls.certresolver=le"
|
||||||
|
depends_on:
|
||||||
|
- template-frontend-app
|
||||||
31
docker/docker-compose.yml.dist
Normal file
31
docker/docker-compose.yml.dist
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
networks:
|
||||||
|
template:
|
||||||
|
external: true
|
||||||
|
|
||||||
|
services:
|
||||||
|
template-frontend-app:
|
||||||
|
image: template-frontend-app
|
||||||
|
networks:
|
||||||
|
- template
|
||||||
|
volumes:
|
||||||
|
- ./../:/var/www/html
|
||||||
|
build:
|
||||||
|
context: ./../
|
||||||
|
dockerfile: ./docker/npm/dockerfile
|
||||||
|
tty: true
|
||||||
|
|
||||||
|
template-frontend-nginx:
|
||||||
|
image: template-frontend-nginx
|
||||||
|
networks:
|
||||||
|
- template
|
||||||
|
volumes:
|
||||||
|
- ./../:/var/www/html
|
||||||
|
build:
|
||||||
|
context: ./../
|
||||||
|
dockerfile: ./docker/nginx/dockerfile
|
||||||
|
labels:
|
||||||
|
- "traefik.http.routers.frontend.rule=Host(`template.local`)"
|
||||||
|
- "traefik.http.routers.frontend.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.frontend.tls.certresolver=le"
|
||||||
|
depends_on:
|
||||||
|
- template-frontend-app
|
||||||
27
docker/nginx/config/nginx.conf
Normal file
27
docker/nginx/config/nginx.conf
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
upstream host-backend-nginx {
|
||||||
|
server template-backend-nginx:80;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
server{
|
||||||
|
listen 80 default_server;
|
||||||
|
|
||||||
|
client_max_body_size 10000M;
|
||||||
|
|
||||||
|
root /var/www/html/dist;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri$args $uri$args/ /index.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /api/ {
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header X-NginX-Proxy true;
|
||||||
|
|
||||||
|
proxy_pass http://host-backend-nginx;
|
||||||
|
}
|
||||||
|
}
|
||||||
5
docker/nginx/dockerfile
Normal file
5
docker/nginx/dockerfile
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
FROM nginx:alpine
|
||||||
|
|
||||||
|
COPY docker/nginx/config/nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
12
docker/npm/dockerfile
Normal file
12
docker/npm/dockerfile
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
FROM node:20-slim
|
||||||
|
|
||||||
|
WORKDIR /var/www/html
|
||||||
|
|
||||||
|
# confirm installation
|
||||||
|
RUN node -v
|
||||||
|
RUN npm -v
|
||||||
|
|
||||||
|
# use newest npm version
|
||||||
|
RUN npm install npm
|
||||||
|
|
||||||
|
CMD ["/bin/bash"]
|
||||||
14622
package-lock.json
generated
Normal file
14622
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
40
package.json
Normal file
40
package.json
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"name": "template",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"ng": "ng",
|
||||||
|
"build": "ng build",
|
||||||
|
"watch": "ng build --watch --configuration development",
|
||||||
|
"test": "ng test"
|
||||||
|
},
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@angular/animations": "^15.2.10",
|
||||||
|
"@angular/cdk": "^15.2.9",
|
||||||
|
"@angular/common": "^15.2.0",
|
||||||
|
"@angular/compiler": "^15.2.0",
|
||||||
|
"@angular/core": "^15.2.0",
|
||||||
|
"@angular/forms": "^15.2.0",
|
||||||
|
"@angular/material": "^15.2.9",
|
||||||
|
"@angular/platform-browser": "^15.2.0",
|
||||||
|
"@angular/platform-browser-dynamic": "^15.2.0",
|
||||||
|
"@angular/router": "^15.2.0",
|
||||||
|
"rxjs": "~7.8.0",
|
||||||
|
"tslib": "^2.3.0",
|
||||||
|
"zone.js": "~0.12.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@angular-devkit/build-angular": "^15.2.6",
|
||||||
|
"@angular/cli": "~15.2.6",
|
||||||
|
"@angular/compiler-cli": "^15.2.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",
|
||||||
|
"tailwindcss": "^3.4.3",
|
||||||
|
"typescript": "~4.9.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
1
src/app/app.component.html
Normal file
1
src/app/app.component.html
Normal file
@ -0,0 +1 @@
|
|||||||
|
<router-outlet></router-outlet>
|
||||||
0
src/app/app.component.scss
Normal file
0
src/app/app.component.scss
Normal file
9
src/app/app.component.ts
Normal file
9
src/app/app.component.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-root',
|
||||||
|
templateUrl: './app.component.html',
|
||||||
|
styleUrls: ['./app.component.scss']
|
||||||
|
})
|
||||||
|
export class AppComponent {
|
||||||
|
}
|
||||||
30
src/app/app.module.ts
Normal file
30
src/app/app.module.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
|
|
||||||
|
import { AppComponent } from './app.component';
|
||||||
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
|
import { SharedModule } from './shared/shared.module';
|
||||||
|
import { HomeComponent } from './core/components/home/home.component';
|
||||||
|
import { CoreModule } from './core/core.module';
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
{ path: 'home', component: HomeComponent },
|
||||||
|
{ path: '', redirectTo: 'home', pathMatch: 'full' },
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [AppComponent],
|
||||||
|
imports: [
|
||||||
|
BrowserModule,
|
||||||
|
BrowserAnimationsModule,
|
||||||
|
HttpClientModule,
|
||||||
|
RouterModule.forRoot(routes),
|
||||||
|
SharedModule,
|
||||||
|
CoreModule,
|
||||||
|
],
|
||||||
|
providers: [],
|
||||||
|
bootstrap: [AppComponent],
|
||||||
|
})
|
||||||
|
export class AppModule {}
|
||||||
21
src/app/app.service.ts
Normal file
21
src/app/app.service.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class AppService {
|
||||||
|
|
||||||
|
private username: string|null;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.username = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getUsername(): string|null {
|
||||||
|
return this.username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setUsername(name: string|null): void {
|
||||||
|
this.username = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
5
src/app/core/components/home/home.component.html
Normal file
5
src/app/core/components/home/home.component.html
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<app-navigation></app-navigation>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
Home
|
||||||
|
</div>
|
||||||
0
src/app/core/components/home/home.component.scss
Normal file
0
src/app/core/components/home/home.component.scss
Normal file
12
src/app/core/components/home/home.component.ts
Normal file
12
src/app/core/components/home/home.component.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { RequestService } from 'src/app/core/services/request.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-home',
|
||||||
|
templateUrl: './home.component.html',
|
||||||
|
styleUrls: ['./home.component.scss'],
|
||||||
|
})
|
||||||
|
export class HomeComponent {
|
||||||
|
constructor(public requestService: RequestService) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
<a routerLink="/home">
|
||||||
|
<h1 class="w-full bg-zinc-700 p-5 text-white text-6xl font-bold text-center">
|
||||||
|
Navigation
|
||||||
|
</h1>
|
||||||
|
</a>
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-navigation',
|
||||||
|
templateUrl: './navigation.component.html',
|
||||||
|
styleUrls: ['./navigation.component.scss'],
|
||||||
|
})
|
||||||
|
export class NavigationComponent {
|
||||||
|
}
|
||||||
15
src/app/core/core.module.ts
Normal file
15
src/app/core/core.module.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { HomeComponent } from './components/home/home.component';
|
||||||
|
import { NavigationComponent } from './components/navigation/navigation.component';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [HomeComponent, NavigationComponent],
|
||||||
|
exports: [HomeComponent, NavigationComponent],
|
||||||
|
imports: [
|
||||||
|
CommonModule
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class CoreModule { }
|
||||||
105
src/app/core/services/request.service.ts
Normal file
105
src/app/core/services/request.service.ts
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class RequestService {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private http: HttpClient,
|
||||||
|
private router: Router,
|
||||||
|
private snackBar: MatSnackBar
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
post(apiPath: string, body: any, fct: Function)
|
||||||
|
{
|
||||||
|
let url = this.obtainUrl(apiPath);
|
||||||
|
let observable = this.http.post(url, body).subscribe(
|
||||||
|
(answer:any) => {
|
||||||
|
fct(answer);
|
||||||
|
},
|
||||||
|
(error:any) => {
|
||||||
|
this.handleError(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
postFiles(apiPath: string, files: File[], fct: Function) {
|
||||||
|
if (!files || files.length === 0) {
|
||||||
|
throw 'Need to select at least one file';
|
||||||
|
}
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
|
||||||
|
for (let fileIndex = 0; fileIndex < files.length; fileIndex++) {
|
||||||
|
formData.append('file' + fileIndex, files[fileIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let url = this.obtainUrl(apiPath);
|
||||||
|
let observable = this.http.post<any>(url, formData).subscribe(
|
||||||
|
(answer: any) => {
|
||||||
|
fct(answer);
|
||||||
|
},
|
||||||
|
(error: any) => {
|
||||||
|
this.handleError(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
get(apiPath: string, body: any, fct: Function)
|
||||||
|
{
|
||||||
|
let url = this.obtainUrl(apiPath);
|
||||||
|
let observable = this.http.get(url, body).subscribe(
|
||||||
|
(answer:any) => {
|
||||||
|
fct(answer);
|
||||||
|
},
|
||||||
|
(error:any) => {
|
||||||
|
this.handleError(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private obtainUrl(apiPath: string): string {
|
||||||
|
let hostString = window.location.host;
|
||||||
|
let protocol = window.location.protocol;
|
||||||
|
return protocol + '//' + hostString + '/api/' + apiPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleError(answer: any): void {
|
||||||
|
|
||||||
|
if (answer.status == 401) {
|
||||||
|
console.log('Deine Sitzung konnte nicht gefunden werden');
|
||||||
|
this.router.navigate(['/auth']);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (answer.status == 403) {
|
||||||
|
this.showSnackBar('Du bist nicht für diese Aktion autorisiert', 'Ok');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
let errorObject = answer.error.error;
|
||||||
|
|
||||||
|
if (errorObject.hasOwnProperty('message')) {
|
||||||
|
throw errorObject.message.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errorObject.hasOwnProperty('code')) {
|
||||||
|
throw errorObject.code.toString();
|
||||||
|
}
|
||||||
|
} catch(error:any) {
|
||||||
|
this.showSnackBar(error.toString(), 'Ok');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private showSnackBar(message: string, action?: string) {
|
||||||
|
this.snackBar.open(message.toString(), action, {
|
||||||
|
duration: 3000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
31
src/app/shared/components/card/card.component.html
Normal file
31
src/app/shared/components/card/card.component.html
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<div
|
||||||
|
id="card"
|
||||||
|
class="grow p-3 my-2 rounded-xl shadow-lg border border-gray-100 dark:bg-zinc-800 dark:border-zinc-900"
|
||||||
|
>
|
||||||
|
<div id="header">
|
||||||
|
<div class="flex flex-row">
|
||||||
|
<div *ngIf="icon !== null">
|
||||||
|
<img class="h-6 w-6 m-2" [src]="icon" />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
*ngIf="header !== null"
|
||||||
|
class="my-auto text-xl font-medium text-black dark:text-white truncate"
|
||||||
|
>
|
||||||
|
{{ header }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
*ngIf="subHeader !== null"
|
||||||
|
class="text-slate-500 dark:text-slate-400 mx-2"
|
||||||
|
>
|
||||||
|
{{ subHeader }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="content" class="mx-5 text-black dark:text-white">
|
||||||
|
<div *ngIf="content !== null" class="my-2 italic">"{{ content }}"</div>
|
||||||
|
<div *ngIf="content === null">
|
||||||
|
<ng-content></ng-content>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
0
src/app/shared/components/card/card.component.scss
Normal file
0
src/app/shared/components/card/card.component.scss
Normal file
13
src/app/shared/components/card/card.component.ts
Normal file
13
src/app/shared/components/card/card.component.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'shared-card',
|
||||||
|
templateUrl: './card.component.html',
|
||||||
|
styleUrls: ['./card.component.scss'],
|
||||||
|
})
|
||||||
|
export class CardComponent {
|
||||||
|
@Input() header: string | null = null;
|
||||||
|
@Input() icon: string | null = null;
|
||||||
|
@Input() subHeader: string | null = null;
|
||||||
|
@Input() content: string | null = null;
|
||||||
|
}
|
||||||
21
src/app/shared/components/form/form.component.html
Normal file
21
src/app/shared/components/form/form.component.html
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<div
|
||||||
|
*ngIf="caption !== null"
|
||||||
|
class="text-lg font-bold mb-3 text-black dark:text-white"
|
||||||
|
>
|
||||||
|
{{ caption }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col md:space-x-4">
|
||||||
|
<div id="form-body" class="flex-1 basis-full">
|
||||||
|
<ng-content />
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-row">
|
||||||
|
<div class="flex-1"></div>
|
||||||
|
<button
|
||||||
|
(click)="submit.emit()"
|
||||||
|
class="flex-0 p-2 min-w-24 bg-green-700 hover:bg-green-800 dark:bg-green-800 dark:hover:bg-green-900 rounded-lg"
|
||||||
|
>
|
||||||
|
<p class="text-lg text-white text-md font-bold">Submit</p>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
0
src/app/shared/components/form/form.component.scss
Normal file
0
src/app/shared/components/form/form.component.scss
Normal file
12
src/app/shared/components/form/form.component.ts
Normal file
12
src/app/shared/components/form/form.component.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'shared-form',
|
||||||
|
templateUrl: './form.component.html',
|
||||||
|
styleUrls: ['./form.component.scss']
|
||||||
|
})
|
||||||
|
export class FormComponent {
|
||||||
|
@Output() submit = new EventEmitter<any>();
|
||||||
|
@Input() caption: string|null = null;
|
||||||
|
|
||||||
|
}
|
||||||
69
src/app/shared/components/paginator/paginator.component.html
Normal file
69
src/app/shared/components/paginator/paginator.component.html
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<nav aria-label="Page navigation example">
|
||||||
|
<ul class="flex items-center -space-x-px h-8 text-sm">
|
||||||
|
<li>
|
||||||
|
<button
|
||||||
|
(click)="setActivePage(-1)"
|
||||||
|
class="flex items-center justify-center px-3 h-8 ms-0 leading-tight text-gray-500 dark:text-white bg-white dark:bg-zinc-800 border border-e-0 border-gray-500 dark:border-zinc-800 rounded-s-lg hover:bg-gray-100 hover:text-gray-700"
|
||||||
|
>
|
||||||
|
<span class="sr-only">Previous</span>
|
||||||
|
<svg
|
||||||
|
class="w-2.5 h-2.5 rtl:rotate-180"
|
||||||
|
aria-hidden="true"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 6 10"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M5 1 1 5l4 4"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li *ngFor="let item of items" class="w-full">
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-center h-8 leading-tight border border-gray-500 dark:border-zinc-800"
|
||||||
|
[ngClass]="{
|
||||||
|
'bg-green-700 dark:bg-green-800 text-white': item.page === page,
|
||||||
|
'bg-white dark:bg-zinc-700 text-black dark:text-white':
|
||||||
|
item.page !== page
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div *ngIf="item.page === null" class="px-3">...</div>
|
||||||
|
<button
|
||||||
|
class="px-3 w-full h-full hover:bg-gray-100 hover:text-gray-700"
|
||||||
|
*ngIf="item.page !== null"
|
||||||
|
(click)="setActivePage(item.page)"
|
||||||
|
>
|
||||||
|
{{ item.page }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<button
|
||||||
|
(click)="setActivePage(-2)"
|
||||||
|
class="flex items-center justify-center px-3 h-8 leading-tight text-gray-500 dark:text-white bg-white dark:bg-zinc-800 border border-gray-500 dark:border-zinc-800 rounded-e-lg hover:bg-gray-100 hover:text-gray-700"
|
||||||
|
>
|
||||||
|
<span class="sr-only">Next</span>
|
||||||
|
<svg
|
||||||
|
class="w-2.5 h-2.5 rtl:rotate-180"
|
||||||
|
aria-hidden="true"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 6 10"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="m1 9 4-4-4-4"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
80
src/app/shared/components/paginator/paginator.component.ts
Normal file
80
src/app/shared/components/paginator/paginator.component.ts
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import {
|
||||||
|
Component,
|
||||||
|
EventEmitter,
|
||||||
|
Input,
|
||||||
|
OnChanges,
|
||||||
|
Output,
|
||||||
|
SimpleChanges,
|
||||||
|
} from '@angular/core';
|
||||||
|
|
||||||
|
export interface PaginatorItem {
|
||||||
|
page: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'shared-paginator',
|
||||||
|
templateUrl: './paginator.component.html',
|
||||||
|
styleUrls: ['./paginator.component.scss'],
|
||||||
|
})
|
||||||
|
export class PaginatorComponent implements OnChanges {
|
||||||
|
@Output() pageChange = new EventEmitter<number>();
|
||||||
|
@Input() page: number = 1;
|
||||||
|
@Input() perPage: number = 10;
|
||||||
|
@Input() total: number | null = null;
|
||||||
|
items: PaginatorItem[] = [];
|
||||||
|
|
||||||
|
ngOnChanges(changes: SimpleChanges): void {
|
||||||
|
this.calculateItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected setActivePage(newPage: number | null) {
|
||||||
|
if (newPage === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (newPage === -1) {
|
||||||
|
newPage = this.page - 1;
|
||||||
|
}
|
||||||
|
if (newPage === -2) {
|
||||||
|
newPage = this.page + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newPage <= 0 || newPage > this.getMaxPages()) return;
|
||||||
|
|
||||||
|
this.page = newPage;
|
||||||
|
this.pageChange.emit(newPage);
|
||||||
|
this.calculateItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
private calculateItems(): void {
|
||||||
|
this.items = [];
|
||||||
|
|
||||||
|
let first = 1;
|
||||||
|
let last = this.getMaxPages();
|
||||||
|
let rangeFirst = this.page - 1;
|
||||||
|
let rangeLast = this.page + 1;
|
||||||
|
|
||||||
|
if (this.page === 1) {
|
||||||
|
rangeFirst = 1;
|
||||||
|
rangeLast = last < 3 ? last : 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.page === last) {
|
||||||
|
rangeFirst = Math.max(1, last - 2);
|
||||||
|
rangeLast = last;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rangeFirst > 1) this.items.push({ page: first });
|
||||||
|
if (rangeFirst > 2) this.items.push({ page: null });
|
||||||
|
|
||||||
|
for (let index = rangeFirst; index <= rangeLast; index++) {
|
||||||
|
this.items.push({ page: index });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rangeLast < last - 1) this.items.push({ page: null });
|
||||||
|
if (rangeLast < last) this.items.push({ page: last });
|
||||||
|
}
|
||||||
|
|
||||||
|
private getMaxPages(): number {
|
||||||
|
return Math.ceil((this.total ?? 0) / this.perPage);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
<div class="text-sm font-medium text-center text-gray-500">
|
||||||
|
<ul class="flex flex-wrap -mb-px">
|
||||||
|
<li *ngFor="let tab of tabs; index as currentIndex" class="grow lg:grow-0">
|
||||||
|
<button
|
||||||
|
(click)="setActiveTab(tab)"
|
||||||
|
class="w-full lg:w-auto text-xl font-bold inline-block px-4 pt-4 pb-3 border-b-2 rounded-t-lg hover:text-green-700 hover:border-green-700 hover:no-underline dark:hover:text-green-800 dark:hover:border-green-800"
|
||||||
|
[ngClass]="{
|
||||||
|
'text-black border-black dark:text-green-800 dark:border-green-800 hover:text-green-700 dark:hover:border-white dark:hover:text-white':
|
||||||
|
currentIndex === activeIndex
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ tab.title }}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tab-content">
|
||||||
|
<ng-content></ng-content>
|
||||||
|
</div>
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
import { Component, ContentChildren, EventEmitter, Input, Output, QueryList } from '@angular/core';
|
||||||
|
import { TabItem } from '../../models/TabItem';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'shared-tab-control',
|
||||||
|
templateUrl: './tab-control.component.html',
|
||||||
|
styleUrls: ['./tab-control.component.scss']
|
||||||
|
})
|
||||||
|
export class TabControlComponent {
|
||||||
|
@Input() public tabs: TabItem[] = [];
|
||||||
|
@Input() public activeTabId: string = '';
|
||||||
|
@Output() public activeTabIdChange = new EventEmitter<string>();
|
||||||
|
|
||||||
|
@ContentChildren('tabContent') tabContents!: QueryList<any>;
|
||||||
|
|
||||||
|
public activeIndex = 0;
|
||||||
|
|
||||||
|
public ngOnChanges() {
|
||||||
|
this.setActiveTab(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public setActiveTab(tab: TabItem|null) {
|
||||||
|
if (tab !== null) {
|
||||||
|
this.activeTabId = tab.id;
|
||||||
|
this.activeTabIdChange.emit(this.activeTabId);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.activeIndex = this.tabs.findIndex((i) => i.id === this.activeTabId);
|
||||||
|
}
|
||||||
|
}
|
||||||
54
src/app/shared/components/table/table.component.html
Normal file
54
src/app/shared/components/table/table.component.html
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<table class="w-full" [ngClass]="[background, foreground, border]">
|
||||||
|
<thead class="uppercase border-b text-sm" [ngClass]="[border]">
|
||||||
|
<tr>
|
||||||
|
<th
|
||||||
|
*ngFor="let column of columns; index as currentIndex"
|
||||||
|
[class]="'px-5 py-2 ' + column.headerCss"
|
||||||
|
[ngClass]="{
|
||||||
|
backgroundColumn: currentIndex % 2 === 0,
|
||||||
|
backgroundColumnAlternate: currentIndex % 2 === 1
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div [innerHtml]="column.header"></div>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr *ngFor="let item of items" class="border-b" [ngClass]="[border]">
|
||||||
|
<td
|
||||||
|
*ngFor="let column of columns; index as currentIndex"
|
||||||
|
[class]="'px-5 py-2 ' + column.columnCss"
|
||||||
|
[ngClass]="{
|
||||||
|
backgroundColumn: currentIndex % 2 === 0,
|
||||||
|
backgroundColumnAlternate: currentIndex % 2 === 1
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div *ngIf="column.routerLink !== undefined">
|
||||||
|
<a [routerLink]="column.routerLink(item)">
|
||||||
|
<div *ngIf="column.columnContent !== undefined">
|
||||||
|
{{ column.columnContent }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
*ngIf="column.columnFunction !== undefined"
|
||||||
|
[innerHtml]="column.columnFunction(item)"
|
||||||
|
></div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="column.routerLink === undefined">
|
||||||
|
<div *ngIf="column.columnContent !== undefined">
|
||||||
|
<div *ngIf="isBoolean(column.columnContent)">
|
||||||
|
<input type="checkbox" [(ngModel)]="column.columnContent" />
|
||||||
|
</div>
|
||||||
|
<div *ngIf="!isBoolean(column.columnContent)">
|
||||||
|
{{ column.columnContent }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
*ngIf="column.columnFunction !== undefined"
|
||||||
|
[innerHtml]="column.columnFunction(item)"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
31
src/app/shared/components/table/table.component.ts
Normal file
31
src/app/shared/components/table/table.component.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { Component, Input } from '@angular/core';
|
||||||
|
|
||||||
|
export interface ColumnDefinition {
|
||||||
|
header: string;
|
||||||
|
columnContent?: string | undefined;
|
||||||
|
columnFunction?: Function | undefined;
|
||||||
|
routerLink?: Function | undefined;
|
||||||
|
headerCss?: string | undefined;
|
||||||
|
columnCss?: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'shared-table',
|
||||||
|
templateUrl: './table.component.html',
|
||||||
|
styleUrls: ['./table.component.scss'],
|
||||||
|
})
|
||||||
|
export class TableComponent {
|
||||||
|
@Input() foreground: string = 'text-white';
|
||||||
|
@Input() background: string = 'bg-zinc-800';
|
||||||
|
@Input() backgroundColumn: string = 'bg-zinc-800';
|
||||||
|
@Input() backgroundColumnAlternate: string = 'bg-zinc-700';
|
||||||
|
@Input() border: string = 'border-zinc-600';
|
||||||
|
|
||||||
|
@Input() items: any[] = [];
|
||||||
|
@Input() columns: ColumnDefinition[] = [];
|
||||||
|
|
||||||
|
isBoolean(obje: any): boolean {
|
||||||
|
console.log(obje);
|
||||||
|
return typeof obje === 'boolean';
|
||||||
|
}
|
||||||
|
}
|
||||||
4
src/app/shared/models/TabItem.ts
Normal file
4
src/app/shared/models/TabItem.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export interface TabItem {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
}
|
||||||
97
src/app/shared/shared.module.ts
Normal file
97
src/app/shared/shared.module.ts
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { RouterModule } from '@angular/router';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { FormComponent } from './components/form/form.component';
|
||||||
|
import { CardComponent } from './components/card/card.component';
|
||||||
|
import { PaginatorComponent } from './components/paginator/paginator.component';
|
||||||
|
import { TabControlComponent } from './components/tab-control/tab-control.component';
|
||||||
|
import { TableComponent } from './components/table/table.component';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { MatInputModule } from '@angular/material/input';
|
||||||
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
|
import { MatSidenavModule } from '@angular/material/sidenav';
|
||||||
|
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||||
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
|
import { MatListModule } from '@angular/material/list';
|
||||||
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
import { MatGridListModule } from '@angular/material/grid-list';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { MatCardModule } from '@angular/material/card';
|
||||||
|
import { MatExpansionModule } from '@angular/material/expansion';
|
||||||
|
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
||||||
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
|
import { MatDividerModule } from '@angular/material/divider';
|
||||||
|
import { MatDialogModule } from '@angular/material/dialog';
|
||||||
|
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||||
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||||
|
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||||
|
import { MatTabsModule } from '@angular/material/tabs';
|
||||||
|
import { MatTableModule } from '@angular/material/table';
|
||||||
|
import { MatChipsModule } from '@angular/material/chips';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
CardComponent,
|
||||||
|
TabControlComponent,
|
||||||
|
PaginatorComponent,
|
||||||
|
FormComponent,
|
||||||
|
TableComponent,
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
CardComponent,
|
||||||
|
TabControlComponent,
|
||||||
|
PaginatorComponent,
|
||||||
|
FormComponent,
|
||||||
|
TableComponent,
|
||||||
|
|
||||||
|
MatSlideToggleModule,
|
||||||
|
MatCardModule,
|
||||||
|
MatButtonModule,
|
||||||
|
MatIconModule,
|
||||||
|
MatGridListModule,
|
||||||
|
MatFormFieldModule,
|
||||||
|
FormsModule,
|
||||||
|
MatExpansionModule,
|
||||||
|
MatMenuModule,
|
||||||
|
MatListModule,
|
||||||
|
MatToolbarModule,
|
||||||
|
MatSidenavModule,
|
||||||
|
MatInputModule,
|
||||||
|
MatSelectModule,
|
||||||
|
MatDividerModule,
|
||||||
|
MatDialogModule,
|
||||||
|
MatSnackBarModule,
|
||||||
|
MatPaginatorModule,
|
||||||
|
MatCheckboxModule,
|
||||||
|
MatTabsModule,
|
||||||
|
MatTableModule,
|
||||||
|
MatChipsModule,
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
RouterModule,
|
||||||
|
CommonModule,
|
||||||
|
MatSlideToggleModule,
|
||||||
|
MatCardModule,
|
||||||
|
MatButtonModule,
|
||||||
|
MatIconModule,
|
||||||
|
MatGridListModule,
|
||||||
|
MatFormFieldModule,
|
||||||
|
FormsModule,
|
||||||
|
MatExpansionModule,
|
||||||
|
MatMenuModule,
|
||||||
|
MatListModule,
|
||||||
|
MatToolbarModule,
|
||||||
|
MatSidenavModule,
|
||||||
|
MatInputModule,
|
||||||
|
MatSelectModule,
|
||||||
|
MatDividerModule,
|
||||||
|
MatDialogModule,
|
||||||
|
MatSnackBarModule,
|
||||||
|
MatPaginatorModule,
|
||||||
|
MatCheckboxModule,
|
||||||
|
MatTabsModule,
|
||||||
|
MatTableModule,
|
||||||
|
MatChipsModule,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class SharedModule {}
|
||||||
BIN
src/assets/icon.ico
Normal file
BIN
src/assets/icon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
BIN
src/favicon.ico
Normal file
BIN
src/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
15
src/index.html
Normal file
15
src/index.html
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>Template</title>
|
||||||
|
<base href="/" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<link rel="icon" type="image/x-icon" href="assets/icon.ico" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" />
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/flowbite/2.3.0/flowbite.min.js"></script>
|
||||||
|
</head>
|
||||||
|
<body class="bg-zinc-900">
|
||||||
|
<app-root></app-root>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
7
src/main.ts
Normal file
7
src/main.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||||
|
|
||||||
|
import { AppModule } from './app/app.module';
|
||||||
|
|
||||||
|
|
||||||
|
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||||
|
.catch(err => console.error(err));
|
||||||
3
src/styles.scss
Normal file
3
src/styles.scss
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
9
tailwind.config.js
Normal file
9
tailwind.config.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
module.exports = {
|
||||||
|
content: ["./src/**/*.{html,ts}"],
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
}
|
||||||
|
|
||||||
14
tsconfig.app.json
Normal file
14
tsconfig.app.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./out-tsc/app",
|
||||||
|
"types": []
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"src/main.ts"
|
||||||
|
],
|
||||||
|
"include": [
|
||||||
|
"src/**/*.d.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
33
tsconfig.json
Normal file
33
tsconfig.json
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||||
|
{
|
||||||
|
"compileOnSave": false,
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": "./",
|
||||||
|
"outDir": "./dist/out-tsc",
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"strict": true,
|
||||||
|
"noImplicitOverride": true,
|
||||||
|
"noPropertyAccessFromIndexSignature": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"declaration": false,
|
||||||
|
"downlevelIteration": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"importHelpers": true,
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "ES2022",
|
||||||
|
"useDefineForClassFields": false,
|
||||||
|
"lib": [
|
||||||
|
"ES2022",
|
||||||
|
"dom"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"angularCompilerOptions": {
|
||||||
|
"enableI18nLegacyMessageIdFormat": false,
|
||||||
|
"strictInjectionParameters": true,
|
||||||
|
"strictInputAccessModifiers": true,
|
||||||
|
"strictTemplates": true
|
||||||
|
}
|
||||||
|
}
|
||||||
14
tsconfig.spec.json
Normal file
14
tsconfig.spec.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./out-tsc/spec",
|
||||||
|
"types": [
|
||||||
|
"jasmine"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.d.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user