generated from flo/template-frontend
Compare commits
2 Commits
5dd8aee455
...
bdb6299692
| Author | SHA1 | Date | |
|---|---|---|---|
| bdb6299692 | |||
| 0adf0a9bfc |
@ -47,10 +47,11 @@
|
||||
"src/favicon.ico"
|
||||
],
|
||||
"styles": [
|
||||
"@angular/material/prebuilt-themes/deeppurple-amber.css",
|
||||
"src/styles.scss"
|
||||
],
|
||||
"scripts": []
|
||||
"scripts": [
|
||||
"node_modules/flowbite/dist/flowbite.min.js"
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
@ -110,7 +111,6 @@
|
||||
"src/favicon.ico"
|
||||
],
|
||||
"styles": [
|
||||
"@angular/material/prebuilt-themes/deeppurple-amber.scss",
|
||||
"src/styles.scss"
|
||||
],
|
||||
"scripts": []
|
||||
|
||||
@ -15,10 +15,10 @@
|
||||
"@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",
|
||||
"flowbite": "^2.5.1",
|
||||
"rxjs": "~7.8.0",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.12.0"
|
||||
@ -34,7 +34,7 @@
|
||||
"karma-coverage": "~2.2.0",
|
||||
"karma-jasmine": "~5.1.0",
|
||||
"karma-jasmine-html-reporter": "~2.0.0",
|
||||
"tailwindcss": "^3.4.3",
|
||||
"tailwindcss": "^3.4.10",
|
||||
"typescript": "~4.9.4"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,18 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { AuthService } from './core/services/auth.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.scss']
|
||||
})
|
||||
export class AppComponent {
|
||||
export class AppComponent implements OnInit {
|
||||
constructor(
|
||||
private authService: AuthService
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.authService.readUserState();
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,9 +8,11 @@ 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';
|
||||
import { AuthGuard } from './core/guards/auth.guard';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: 'home', component: HomeComponent },
|
||||
{ path: 'auth', loadChildren: () => import('./core/auth/auth.module').then(m => m.AuthModule) },
|
||||
{ path: 'home', component: HomeComponent, canActivate: [AuthGuard] },
|
||||
{ path: '', redirectTo: 'home', pathMatch: 'full' },
|
||||
];
|
||||
|
||||
|
||||
33
src/app/core/auth/auth.module.ts
Normal file
33
src/app/core/auth/auth.module.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { LoginComponent } from './components/login/login.component';
|
||||
import { RegistrationComponent } from './components/registration/registration.component';
|
||||
import { ConfirmRegistrationComponent } from './components/confirm-registration/confirm-registration.component';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: 'login', component: LoginComponent },
|
||||
{ path: 'registration', component: RegistrationComponent },
|
||||
{ path: 'registration/:id', component: ConfirmRegistrationComponent },
|
||||
{ path: '', redirectTo: 'login', pathMatch: 'full' },
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
LoginComponent,
|
||||
RegistrationComponent,
|
||||
ConfirmRegistrationComponent
|
||||
],
|
||||
exports: [
|
||||
LoginComponent,
|
||||
RegistrationComponent,
|
||||
ConfirmRegistrationComponent
|
||||
],
|
||||
imports: [
|
||||
RouterModule.forChild(routes),
|
||||
CommonModule,
|
||||
ReactiveFormsModule
|
||||
]
|
||||
})
|
||||
export class AuthModule { }
|
||||
@ -0,0 +1 @@
|
||||
<p>confirm-registration works!</p>
|
||||
@ -0,0 +1,10 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-confirm-registration',
|
||||
templateUrl: './confirm-registration.component.html',
|
||||
styleUrls: ['./confirm-registration.component.scss']
|
||||
})
|
||||
export class ConfirmRegistrationComponent {
|
||||
|
||||
}
|
||||
24
src/app/core/auth/components/login/login.component.html
Normal file
24
src/app/core/auth/components/login/login.component.html
Normal file
@ -0,0 +1,24 @@
|
||||
<div class="mb-10">
|
||||
</div>
|
||||
|
||||
<div class="max-w-sm mx-auto mb-10">
|
||||
<h1 class="font-bold text-center text-skin-primary text-5xl mb-5">
|
||||
Beekeeper
|
||||
</h1>
|
||||
<h1 class="font-bold text-center text-skin-accent text-xl">
|
||||
Anmeldung
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<form class="max-w-sm mx-auto" [formGroup]="loginForm">
|
||||
<div class="mb-5">
|
||||
<label for="identifier" class="block mb-2 text-sm font-medium text-skin-primary-muted">Benutzername oder E-Mail</label>
|
||||
<input formControlName="identifier" type="text" id="identifier" class="bg-skin-primary border border-gray-300 text-skin-primary text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5" placeholder="username72 / your@email.com" required />
|
||||
</div>
|
||||
<div class="mb-5">
|
||||
<label for="password" class="block mb-2 text-sm font-medium text-skin-primary-muted">Passwort</label>
|
||||
<input formControlName="password" type="password" id="password" class="bg-skin-primary border border-gray-300 text-skin-primary text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5" required />
|
||||
<p id="helper-text-explanation" class="mt-2 text-sm text-skin-primary-muted">Neu hier? <a routerLink="/auth/registration" class="font-medium text-skin-accent hover:underline hover:font-bold">Jetzt registrieren!</a></p>
|
||||
</div>
|
||||
<button (click)="login()" [disabled]="!loginForm.valid" type="submit" class="w-full 9xl:w-auto font-bold text-skin-primary bg-skin-secondary hover:text-skin-secondary rounded-lg text-sm px-5 py-2.5 text-center">Anmelden</button>
|
||||
</form>
|
||||
35
src/app/core/auth/components/login/login.component.ts
Normal file
35
src/app/core/auth/components/login/login.component.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
import { Router } from '@angular/router';
|
||||
import { filter } from 'rxjs';
|
||||
import { AuthService } from 'src/app/core/services/auth.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-login',
|
||||
templateUrl: './login.component.html',
|
||||
styleUrls: ['./login.component.scss']
|
||||
})
|
||||
export class LoginComponent {
|
||||
loginForm = new FormGroup({
|
||||
identifier: new FormControl('', [Validators.required]),
|
||||
password: new FormControl('', [Validators.required]),
|
||||
});
|
||||
|
||||
constructor(
|
||||
private authService: AuthService,
|
||||
private router: Router
|
||||
) {
|
||||
this.authService.currentState$.pipe(
|
||||
filter(state => state !== undefined)
|
||||
).subscribe(state => {
|
||||
this.router.navigateByUrl('/home');
|
||||
});
|
||||
}
|
||||
|
||||
login(): void {
|
||||
this.authService.login({
|
||||
identifier: this.loginForm.value.identifier!,
|
||||
password: this.loginForm.value.password!
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
<p>registration works!</p>
|
||||
@ -0,0 +1,10 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-registration',
|
||||
templateUrl: './registration.component.html',
|
||||
styleUrls: ['./registration.component.scss']
|
||||
})
|
||||
export class RegistrationComponent {
|
||||
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
<app-navigation></app-navigation>
|
||||
|
||||
<div>
|
||||
Home
|
||||
<iframe src="/api/health"></iframe>
|
||||
</div>
|
||||
@ -1,5 +1,57 @@
|
||||
<a routerLink="/home">
|
||||
<h1 class="w-full bg-zinc-700 p-5 text-white text-6xl font-bold text-center">
|
||||
Navigation
|
||||
</h1>
|
||||
</a>
|
||||
|
||||
|
||||
<nav class="bg-skin-secondary">
|
||||
<div class="max-w-screen-xl flex flex-wrap items-center justify-between mx-auto p-4">
|
||||
|
||||
<!-- Title -->
|
||||
<a href="#" class="flex items-center space-x-3">
|
||||
<img src="assets/icon.png" class="h-10" alt="Beekeeper Logo" />
|
||||
<span class="text-skin-primary self-center text-2xl font-semibold whitespace-nowrap">Beekeeper</span>
|
||||
</a>
|
||||
|
||||
<div class="flex items-center md:order-2 space-x-3 md:space-x-0">
|
||||
<!--User Bubble-->
|
||||
<button type="button" class="block w-10 h-10 text-sm bg-skin-primary rounded-full md:me-0 focus:ring-4 focus:ring-gray-300" id="user-menu-button" aria-expanded="false" data-dropdown-toggle="user-dropdown" data-dropdown-placement="bottom">
|
||||
<span class="text-skin-accent rounded-full font-bold p-2">AA</span>
|
||||
<!-- <img class="w-8 h-8 rounded-full" src="/docs/images/people/profile-picture-3.jpg" alt="user photo"> -->
|
||||
</button>
|
||||
|
||||
<!--Burger Menu-->
|
||||
<button data-collapse-toggle="navbar-user" type="button" class="inline-flex items-center p-2 w-10 h-10 justify-center text-sm text-skin-primary rounded-lg md:hidden hover:bg-skin-primary" aria-controls="navbar-user" aria-expanded="false">
|
||||
<span class="sr-only">Open main menu</span>
|
||||
<svg class="w-5 h-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 17 14">
|
||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 1h15M1 7h15M1 13h15"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- User dropdown -->
|
||||
<div class="z-50 hidden my-4 text-base list-none divide-y divide-gray-100 rounded-lg shadow-sm shadow-skin-primary bg-skin-primary" id="user-dropdown">
|
||||
<div class="px-4 py-3">
|
||||
<span class="block text-sm text-skin-accent font-bold">{{state?.username}}</span>
|
||||
<span class="block text-sm text-skin-primary-muted truncate">{{state?.roleIdentifier}}</span>
|
||||
</div>
|
||||
<ul class="p-4" aria-labelledby="user-menu-button">
|
||||
<li>
|
||||
<a href="#" class="block py-2 px-3 rounded text-skin-primary hover:bg-skin-secondary">Einstellungen</a>
|
||||
</li>
|
||||
<li>
|
||||
<button class="w-full block py-2 px-3 rounded text-skin-primary hover:bg-skin-secondary" (click)="logout()">Ausloggen</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Navigatoin -->
|
||||
<div class="items-center justify-between hidden w-full md:flex md:w-auto md:order-1" id="navbar-user">
|
||||
<ul class="flex flex-col font-medium p-4 md:p-0 mt-4 rounded-lg bg-skin-primary md:bg-skin-secondary md:space-x-8 md:flex-row md:mt-0 md:border-0 md:bg-skin-fill">
|
||||
<li>
|
||||
<a routerLink="/home" class="block py-2 px-3 rounded text-skin-primary md:p-0" aria-current="page">Home</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" class="block py-2 px-3 rounded text-skin-primary-muted hover:text-skin-primary hover:bg-skin-secondary md:p-0">About</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@ -1,9 +1,36 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { initFlowbite } from 'flowbite';
|
||||
import { AuthService } from '../../services/auth.service';
|
||||
import { UserStateResponse } from '../../models/user-state-request.model';
|
||||
import { Router } from '@angular/router';
|
||||
import { filter, map } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'app-navigation',
|
||||
templateUrl: './navigation.component.html',
|
||||
styleUrls: ['./navigation.component.scss'],
|
||||
})
|
||||
export class NavigationComponent {
|
||||
export class NavigationComponent implements OnInit {
|
||||
|
||||
state: UserStateResponse | undefined | null;
|
||||
|
||||
constructor(
|
||||
private authService: AuthService,
|
||||
private router: Router,
|
||||
) {
|
||||
this.state = this.authService.currentState$.value;
|
||||
this.authService.currentState$.pipe(
|
||||
filter(state => state === undefined)
|
||||
).subscribe( state =>
|
||||
this.router.navigateByUrl('/auth/login')
|
||||
);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
initFlowbite();
|
||||
}
|
||||
|
||||
logout(): void {
|
||||
this.authService.logout();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,9 @@ import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { HomeComponent } from './components/home/home.component';
|
||||
import { NavigationComponent } from './components/navigation/navigation.component';
|
||||
import { AuthGuard } from './guards/auth.guard';
|
||||
import { AuthService } from './services/auth.service';
|
||||
import { RequestService } from './services/request.service';
|
||||
|
||||
|
||||
|
||||
@ -10,6 +13,7 @@ import { NavigationComponent } from './components/navigation/navigation.componen
|
||||
exports: [HomeComponent, NavigationComponent],
|
||||
imports: [
|
||||
CommonModule
|
||||
]
|
||||
],
|
||||
providers: [AuthGuard, AuthService, RequestService]
|
||||
})
|
||||
export class CoreModule { }
|
||||
|
||||
26
src/app/core/guards/auth.guard.ts
Normal file
26
src/app/core/guards/auth.guard.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from "@angular/router";
|
||||
import { filter, map, Observable } from "rxjs";
|
||||
import { AuthService } from "../services/auth.service";
|
||||
|
||||
@Injectable()
|
||||
export class AuthGuard implements CanActivate {
|
||||
|
||||
constructor(
|
||||
private authService: AuthService,
|
||||
private router: Router
|
||||
) {
|
||||
}
|
||||
|
||||
canActivate(): Observable<boolean> | boolean {
|
||||
return this.authService.currentState$.pipe(
|
||||
map((currentState) => {
|
||||
if (!currentState) {
|
||||
this.router.navigateByUrl('/auth');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
8
src/app/core/models/login-request.model copy.ts
Normal file
8
src/app/core/models/login-request.model copy.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export interface LoginRequest {
|
||||
identifier: string,
|
||||
password: string,
|
||||
}
|
||||
|
||||
export interface LoginResponse {
|
||||
sessionId: string
|
||||
}
|
||||
12
src/app/core/models/user-state-request.model.ts
Normal file
12
src/app/core/models/user-state-request.model.ts
Normal file
@ -0,0 +1,12 @@
|
||||
export interface UserStateRequest {
|
||||
}
|
||||
|
||||
export interface UserStateResponse {
|
||||
id: string,
|
||||
sessionId: string,
|
||||
username: string,
|
||||
roleIdentifier: string,
|
||||
createdAt: string,
|
||||
updatedAt: string,
|
||||
permissions: string[],
|
||||
}
|
||||
56
src/app/core/services/auth.service.ts
Normal file
56
src/app/core/services/auth.service.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { RequestService } from "./request.service";
|
||||
import { UserStateResponse } from "../models/user-state-request.model";
|
||||
import { BehaviorSubject, Observable } from "rxjs";
|
||||
import { LoginRequest, LoginResponse } from "../models/login-request.model copy";
|
||||
import { Router } from "@angular/router";
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
|
||||
currentState$ = new BehaviorSubject<UserStateResponse | null | undefined>(undefined);
|
||||
|
||||
constructor(
|
||||
private requestService: RequestService,
|
||||
private router: Router
|
||||
) {
|
||||
}
|
||||
|
||||
readUserState(): void {
|
||||
this.requestService.get(
|
||||
'user/state',
|
||||
{},
|
||||
(response: UserStateResponse) => {
|
||||
this.currentState$.next(response);
|
||||
},
|
||||
() => {
|
||||
this.currentState$.next(undefined);
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
login(body: LoginRequest): LoginResponse|null {
|
||||
let result = null;
|
||||
|
||||
this.requestService.post(
|
||||
'auth/login-user',
|
||||
body,
|
||||
(response: LoginResponse) => {
|
||||
result = response;
|
||||
this.readUserState();
|
||||
}
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
logout(): void {
|
||||
this.requestService.post(
|
||||
'auth/logout-user',
|
||||
{},
|
||||
(response: any) => {
|
||||
this.readUserState();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,6 @@
|
||||
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'
|
||||
@ -11,24 +10,42 @@ export class RequestService {
|
||||
constructor(
|
||||
private http: HttpClient,
|
||||
private router: Router,
|
||||
private snackBar: MatSnackBar
|
||||
) {
|
||||
}
|
||||
|
||||
post(apiPath: string, body: any, fct: Function)
|
||||
public post(apiPath: string, body: any, successFunction: Function, errorFunction: Function|null = null)
|
||||
{
|
||||
let url = this.obtainUrl(apiPath);
|
||||
let observable = this.http.post(url, body).subscribe(
|
||||
(answer:any) => {
|
||||
fct(answer);
|
||||
successFunction(answer);
|
||||
},
|
||||
(error:any) => {
|
||||
if (errorFunction === null)
|
||||
this.handleError(error);
|
||||
else
|
||||
errorFunction(error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
postFiles(apiPath: string, files: File[], fct: Function) {
|
||||
public get(apiPath: string, body: any, successFunction: Function, errorFunction: Function|null = null)
|
||||
{
|
||||
let url = this.obtainUrl(apiPath);
|
||||
let observable = this.http.get(url, body).subscribe(
|
||||
(answer:any) => {
|
||||
successFunction(answer);
|
||||
},
|
||||
(error:any) => {
|
||||
if (errorFunction === null)
|
||||
this.handleError(error);
|
||||
else
|
||||
errorFunction(error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public postFiles(apiPath: string, files: File[], successFunction: Function, errorFunction: Function|null = null) {
|
||||
if (!files || files.length === 0) {
|
||||
throw 'Need to select at least one file';
|
||||
}
|
||||
@ -42,23 +59,13 @@ export class RequestService {
|
||||
let url = this.obtainUrl(apiPath);
|
||||
let observable = this.http.post<any>(url, formData).subscribe(
|
||||
(answer: any) => {
|
||||
fct(answer);
|
||||
successFunction(answer);
|
||||
},
|
||||
(error: any) => {
|
||||
if (errorFunction === null)
|
||||
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);
|
||||
else
|
||||
errorFunction(error);
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -98,8 +105,9 @@ export class RequestService {
|
||||
}
|
||||
|
||||
private showSnackBar(message: string, action?: string) {
|
||||
this.snackBar.open(message.toString(), action, {
|
||||
/*this.snackBar.open(message.toString(), action, {
|
||||
duration: 3000,
|
||||
});
|
||||
});*/
|
||||
console.log(message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,27 +7,6 @@ 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: [
|
||||
@ -44,54 +23,12 @@ import { MatChipsModule } from '@angular/material/chips';
|
||||
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 {}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 66 KiB |
BIN
src/assets/icon.png
Normal file
BIN
src/assets/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.9 KiB |
BIN
src/favicon.ico
BIN
src/favicon.ico
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 66 KiB |
@ -5,11 +5,10 @@
|
||||
<title>Bienen</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="icon" type="image/x-icon" href="assets/icon.png" />
|
||||
<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">
|
||||
<body class="bg-skin-primary">
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -1,3 +1,36 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--color-text-primary: 0,0,0;
|
||||
--color-text-primary-muted: 100,100,100;
|
||||
--color-text-secondary: 255,255,255;
|
||||
--color-text-secondary-muted: 170,170,170;
|
||||
--color-text-accent: 255, 199, 44;
|
||||
--color-text-accent-muted: 255, 199, 44;
|
||||
|
||||
--color-shadow-primary: 100,100,100;
|
||||
|
||||
--color-primary: 255, 255, 255;
|
||||
--color-secondary: 255, 199, 44;
|
||||
--color-accent: 255, 199, 44;
|
||||
}
|
||||
.theme-dark {
|
||||
--color-text-primary: 255,255,255;
|
||||
--color-text-primary-muted: 170,170,170;
|
||||
--color-text-secondary: 0,0,0;
|
||||
--color-text-secondary-muted: 100,100,100;
|
||||
--color-text-accent: 250, 183, 0;
|
||||
--color-text-accent-muted: 250, 183, 0;
|
||||
|
||||
--color-shadow-primary: 170,170,170;
|
||||
|
||||
|
||||
--color-primary: 10, 10, 10;
|
||||
--color-secondary: 250, 183, 0;
|
||||
--color-accent: 250, 183, 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,46 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: ["./src/**/*.{html,ts}"],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
function withOpacity(variableName) {
|
||||
return ({ opacityValue }) => {
|
||||
if (opacityValue !== undefined) {
|
||||
return `rgba(var(${variableName}), ${opacityValue})`
|
||||
}
|
||||
return `rgb(var(${variableName}))`
|
||||
}
|
||||
}
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: [
|
||||
"./src/**/*.{html,ts}",
|
||||
"./node_modules/flowbite/**/*.js"
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
textColor: {
|
||||
skin: {
|
||||
primary: withOpacity('--color-text-primary'),
|
||||
'primary-muted': withOpacity('--color-text-primary-muted'),
|
||||
secondary: withOpacity('--color-text-secondary'),
|
||||
'secondary-muted': withOpacity('--color-text-secondary-muted'),
|
||||
accent: withOpacity('--color-text-accent'),
|
||||
'accent-muted': withOpacity('--color-text-accent-muted'),
|
||||
},
|
||||
},
|
||||
backgroundColor: {
|
||||
skin: {
|
||||
primary: withOpacity('--color-primary'),
|
||||
secondary: withOpacity('--color-secondary'),
|
||||
accent: withOpacity('--color-accent'),
|
||||
},
|
||||
},
|
||||
boxShadowColor: {
|
||||
skin: {
|
||||
primary: withOpacity('--color-shadow-primary'),
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
require('flowbite/plugin')
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user