generated from flo/template-frontend
changes
This commit is contained in:
parent
0499c81924
commit
9145bc245f
@ -1,18 +1,17 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { AuthService } from './core/services/auth.service';
|
||||
import { AppService } from './core/services/app.service';
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { AuthService } from "./core/services/auth.service";
|
||||
import { AppService } from "./core/services/app.service";
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.scss']
|
||||
selector: "app-root",
|
||||
templateUrl: "./app.component.html",
|
||||
styleUrls: ["./app.component.scss"],
|
||||
})
|
||||
export class AppComponent implements OnInit {
|
||||
constructor(
|
||||
private authService: AuthService,
|
||||
private appService: AppService,
|
||||
) {
|
||||
}
|
||||
private appService: AppService
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.authService.readUserState();
|
||||
|
||||
@ -1,21 +1,28 @@
|
||||
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 { 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';
|
||||
import { AuthGuard } from './core/guards/auth.guard';
|
||||
import { SettingsComponent } from './core/components/settings/settings.component';
|
||||
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";
|
||||
import { AuthGuard } from "./core/guards/auth.guard";
|
||||
import { SettingsComponent } from "./core/components/settings/settings.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: 'auth', loadChildren: () => import('./core/auth/auth.module').then(m => m.AuthModule) },
|
||||
{ path: '', component: HomeComponent, canActivate: [AuthGuard], children: [
|
||||
{path: 'settings', component: SettingsComponent}
|
||||
]},
|
||||
{
|
||||
path: "auth",
|
||||
loadChildren: () =>
|
||||
import("./core/auth/auth.module").then((m) => m.AuthModule),
|
||||
},
|
||||
{
|
||||
path: "",
|
||||
component: HomeComponent,
|
||||
canActivate: [AuthGuard],
|
||||
children: [{ path: "settings", component: SettingsComponent }],
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
@ -24,6 +31,7 @@ const routes: Routes = [
|
||||
BrowserModule,
|
||||
BrowserAnimationsModule,
|
||||
HttpClientModule,
|
||||
RouterModule,
|
||||
RouterModule.forRoot(routes),
|
||||
SharedModule,
|
||||
CoreModule,
|
||||
|
||||
@ -1,33 +1,32 @@
|
||||
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';
|
||||
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/:registrationId', component: ConfirmRegistrationComponent },
|
||||
{ path: '', redirectTo: 'login', pathMatch: 'full' },
|
||||
{ path: "login", component: LoginComponent },
|
||||
{ path: "registration", component: RegistrationComponent },
|
||||
{
|
||||
path: "registration/:registrationId",
|
||||
component: ConfirmRegistrationComponent,
|
||||
},
|
||||
{ path: "", redirectTo: "login", pathMatch: "full" },
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
LoginComponent,
|
||||
RegistrationComponent,
|
||||
ConfirmRegistrationComponent
|
||||
ConfirmRegistrationComponent,
|
||||
],
|
||||
exports: [
|
||||
LoginComponent,
|
||||
RegistrationComponent,
|
||||
ConfirmRegistrationComponent
|
||||
ConfirmRegistrationComponent,
|
||||
],
|
||||
imports: [
|
||||
RouterModule.forChild(routes),
|
||||
CommonModule,
|
||||
ReactiveFormsModule
|
||||
]
|
||||
imports: [RouterModule.forChild(routes), CommonModule, ReactiveFormsModule],
|
||||
})
|
||||
export class AuthModule {}
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
<div class="mb-10">
|
||||
</div>
|
||||
<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">
|
||||
@ -12,12 +11,39 @@
|
||||
|
||||
<form class="max-w-sm mx-auto" [formGroup]="confirmRegistrationForm">
|
||||
<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 />
|
||||
<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
|
||||
/>
|
||||
</div>
|
||||
<div class="mb-5">
|
||||
<label for="passwordConfirmation" class="block mb-2 text-sm font-medium text-skin-primary-muted">Passwort wiederholen</label>
|
||||
<input formControlName="passwordConfirmation" type="password" id="passwordConfirmation" 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 />
|
||||
<label
|
||||
for="passwordConfirmation"
|
||||
class="block mb-2 text-sm font-medium text-skin-primary-muted"
|
||||
>Passwort wiederholen</label
|
||||
>
|
||||
<input
|
||||
formControlName="passwordConfirmation"
|
||||
type="password"
|
||||
id="passwordConfirmation"
|
||||
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
|
||||
/>
|
||||
</div>
|
||||
<button (click)="confirm()" [disabled]="!confirmRegistrationForm.valid" type="submit" class="w-full 9xl:w-auto font-bold text-skin-secondary bg-skin-accent hover:text-skin-primary rounded-lg text-sm px-5 py-2.5 text-center">Registrieren</button>
|
||||
<button
|
||||
(click)="confirm()"
|
||||
[disabled]="!confirmRegistrationForm.valid"
|
||||
type="submit"
|
||||
class="w-full 9xl:w-auto font-bold text-skin-secondary bg-skin-accent hover:text-skin-primary rounded-lg text-sm px-5 py-2.5 text-center"
|
||||
>
|
||||
Registrieren
|
||||
</button>
|
||||
</form>
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { filter } from 'rxjs';
|
||||
import { AuthService } from 'src/app/core/services/auth.service';
|
||||
import { Component } from "@angular/core";
|
||||
import { FormControl, FormGroup, Validators } from "@angular/forms";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { filter } from "rxjs";
|
||||
import { AuthService } from "src/app/core/services/auth.service";
|
||||
|
||||
@Component({
|
||||
selector: 'app-confirm-registration',
|
||||
templateUrl: './confirm-registration.component.html',
|
||||
styleUrls: ['./confirm-registration.component.scss']
|
||||
selector: "app-confirm-registration",
|
||||
templateUrl: "./confirm-registration.component.html",
|
||||
styleUrls: ["./confirm-registration.component.scss"],
|
||||
})
|
||||
export class ConfirmRegistrationComponent {
|
||||
confirmRegistrationForm = new FormGroup({
|
||||
password: new FormControl('', [Validators.required]),
|
||||
passwordConfirmation: new FormControl('', [Validators.required]),
|
||||
password: new FormControl("", [Validators.required]),
|
||||
passwordConfirmation: new FormControl("", [Validators.required]),
|
||||
});
|
||||
|
||||
registrationId: string | undefined;
|
||||
@ -22,27 +22,23 @@ export class ConfirmRegistrationComponent {
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private router: Router
|
||||
) {
|
||||
this.activatedRoute.params.subscribe(
|
||||
(params) => {
|
||||
this.registrationId = params['registrationId'];
|
||||
}
|
||||
);
|
||||
this.activatedRoute.params.subscribe((params) => {
|
||||
this.registrationId = params["registrationId"];
|
||||
});
|
||||
|
||||
this.authService.currentState$.pipe(
|
||||
filter(state=>state !== undefined && state !== null)
|
||||
).subscribe((state) =>
|
||||
this.router.navigateByUrl('/')
|
||||
);
|
||||
this.authService.currentState$
|
||||
.pipe(filter((state) => state !== undefined && state !== null))
|
||||
.subscribe((state) => this.router.navigateByUrl("/"));
|
||||
}
|
||||
|
||||
confirm(): void {
|
||||
if (this.registrationId === undefined)
|
||||
return;
|
||||
if (this.registrationId === undefined) return;
|
||||
|
||||
this.authService.confirmRegistration({
|
||||
id: this.registrationId!,
|
||||
password: this.confirmRegistrationForm.value.password!,
|
||||
passwordConfirmation: this.confirmRegistrationForm.value.passwordConfirmation!
|
||||
passwordConfirmation:
|
||||
this.confirmRegistrationForm.value.passwordConfirmation!,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,24 +1,59 @@
|
||||
<div class="mb-10">
|
||||
</div>
|
||||
<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>
|
||||
<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 />
|
||||
<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>
|
||||
<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-secondary bg-skin-accent hover:text-skin-primary rounded-lg text-sm px-5 py-2.5 text-center">Anmelden</button>
|
||||
<button
|
||||
(click)="login()"
|
||||
[disabled]="!loginForm.valid"
|
||||
type="submit"
|
||||
class="w-full 9xl:w-auto font-bold text-skin-secondary bg-skin-accent hover:text-skin-primary rounded-lg text-sm px-5 py-2.5 text-center"
|
||||
>
|
||||
Anmelden
|
||||
</button>
|
||||
</form>
|
||||
|
||||
@ -1,35 +1,30 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
import { Router } from '@angular/router';
|
||||
import { filter, map } from 'rxjs';
|
||||
import { AuthService } from 'src/app/core/services/auth.service';
|
||||
import { Component } from "@angular/core";
|
||||
import { FormControl, FormGroup, Validators } from "@angular/forms";
|
||||
import { Router } from "@angular/router";
|
||||
import { filter, map } from "rxjs";
|
||||
import { AuthService } from "src/app/core/services/auth.service";
|
||||
|
||||
@Component({
|
||||
selector: 'app-login',
|
||||
templateUrl: './login.component.html',
|
||||
styleUrls: ['./login.component.scss']
|
||||
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]),
|
||||
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 && state !== null)
|
||||
).subscribe((state) =>
|
||||
this.router.navigateByUrl('/')
|
||||
);
|
||||
constructor(private authService: AuthService, private router: Router) {
|
||||
this.authService.currentState$
|
||||
.pipe(filter((state) => state !== undefined && state !== null))
|
||||
.subscribe((state) => this.router.navigateByUrl("/"));
|
||||
}
|
||||
|
||||
login(): void {
|
||||
this.authService.login({
|
||||
identifier: this.loginForm.value.identifier!,
|
||||
password: this.loginForm.value.password!
|
||||
password: this.loginForm.value.password!,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,24 +1,59 @@
|
||||
<div class="mb-10">
|
||||
</div>
|
||||
<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">
|
||||
Registrierung
|
||||
</h1>
|
||||
<h1 class="font-bold text-center text-skin-accent text-xl">Registrierung</h1>
|
||||
</div>
|
||||
|
||||
<form class="max-w-sm mx-auto" [formGroup]="registrationForm">
|
||||
<div class="mb-5">
|
||||
<label for="mail" class="block mb-2 text-sm font-medium text-skin-primary-muted">E-Mail</label>
|
||||
<input formControlName="mail" type="mail" id="mail" 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="your@email.com" required />
|
||||
<label
|
||||
for="mail"
|
||||
class="block mb-2 text-sm font-medium text-skin-primary-muted"
|
||||
>E-Mail</label
|
||||
>
|
||||
<input
|
||||
formControlName="mail"
|
||||
type="mail"
|
||||
id="mail"
|
||||
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="your@email.com"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="mb-5">
|
||||
<label for="username" class="block mb-2 text-sm font-medium text-skin-primary-muted">Benutzername</label>
|
||||
<input formControlName="username" type="string" id="username" 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">Bereits registiert? <a routerLink="/auth/login" class="font-medium text-skin-accent hover:underline hover:font-bold">Jetzt anmelden!</a></p>
|
||||
<label
|
||||
for="username"
|
||||
class="block mb-2 text-sm font-medium text-skin-primary-muted"
|
||||
>Benutzername</label
|
||||
>
|
||||
<input
|
||||
formControlName="username"
|
||||
type="string"
|
||||
id="username"
|
||||
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"
|
||||
>
|
||||
Bereits registiert?
|
||||
<a
|
||||
routerLink="/auth/login"
|
||||
class="font-medium text-skin-accent hover:underline hover:font-bold"
|
||||
>Jetzt anmelden!</a
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
<button (click)="register()" [disabled]="!registrationForm.valid" type="submit" class="w-full 9xl:w-auto font-bold text-skin-secondary bg-skin-accent hover:text-skin-primary rounded-lg text-sm px-5 py-2.5 text-center">Registrieren</button>
|
||||
<button
|
||||
(click)="register()"
|
||||
[disabled]="!registrationForm.valid"
|
||||
type="submit"
|
||||
class="w-full 9xl:w-auto font-bold text-skin-secondary bg-skin-accent hover:text-skin-primary rounded-lg text-sm px-5 py-2.5 text-center"
|
||||
>
|
||||
Registrieren
|
||||
</button>
|
||||
</form>
|
||||
|
||||
@ -1,37 +1,32 @@
|
||||
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';
|
||||
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-registration',
|
||||
templateUrl: './registration.component.html',
|
||||
styleUrls: ['./registration.component.scss']
|
||||
selector: "app-registration",
|
||||
templateUrl: "./registration.component.html",
|
||||
styleUrls: ["./registration.component.scss"],
|
||||
})
|
||||
export class RegistrationComponent {
|
||||
registrationForm = new FormGroup({
|
||||
mail: new FormControl('', [Validators.required]),
|
||||
username: new FormControl('', [Validators.required]),
|
||||
mail: new FormControl("", [Validators.required]),
|
||||
username: new FormControl("", [Validators.required]),
|
||||
});
|
||||
|
||||
constructor(
|
||||
private authService: AuthService,
|
||||
private router: Router
|
||||
) {
|
||||
this.authService.currentState$.pipe(
|
||||
filter(state=>state !== undefined && state !== null)
|
||||
).subscribe((state) =>
|
||||
this.router.navigateByUrl('/')
|
||||
);
|
||||
constructor(private authService: AuthService, private router: Router) {
|
||||
this.authService.currentState$
|
||||
.pipe(filter((state) => state !== undefined && state !== null))
|
||||
.subscribe((state) => this.router.navigateByUrl("/"));
|
||||
}
|
||||
|
||||
register(): void {
|
||||
this.authService.register({
|
||||
mail: this.registrationForm.value.mail!,
|
||||
username: this.registrationForm.value.username!
|
||||
username: this.registrationForm.value.username!,
|
||||
});
|
||||
|
||||
this.router.navigateByUrl('/auth/login');
|
||||
this.router.navigateByUrl("/auth/login");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,26 +1,5 @@
|
||||
<app-navigation></app-navigation>
|
||||
|
||||
<div class="max-w-screen-xl mx-auto p-4">
|
||||
<shared-card icon="/assets/icon.png" header="Test" subHeader="lol noch ein test">
|
||||
I'm working
|
||||
</shared-card>
|
||||
|
||||
<shared-card icon="/assets/icon.png" header="Test" >
|
||||
I'm working
|
||||
</shared-card>
|
||||
|
||||
<shared-card>
|
||||
I'm working
|
||||
</shared-card>
|
||||
|
||||
<div class="mb-5">
|
||||
<shared-table [items]="colonies" [columns]="columns">
|
||||
|
||||
</shared-table>
|
||||
</div>
|
||||
|
||||
<shared-paginator total="20" perPage="5" />
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
</div>
|
||||
@ -1,40 +1,8 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { RequestService } from 'src/app/core/services/request.service';
|
||||
import { ColumnDefinition } from 'src/app/shared/components/table/table.component';
|
||||
|
||||
interface Colony {
|
||||
name: string;
|
||||
|
||||
}
|
||||
import { Component } from "@angular/core";
|
||||
|
||||
@Component({
|
||||
selector: 'app-home',
|
||||
templateUrl: './home.component.html',
|
||||
styleUrls: ['./home.component.scss'],
|
||||
selector: "app-home",
|
||||
templateUrl: "./home.component.html",
|
||||
styleUrls: ["./home.component.scss"],
|
||||
})
|
||||
export class HomeComponent {
|
||||
|
||||
columns: ColumnDefinition[] = [
|
||||
{
|
||||
header: 'Name',
|
||||
columnFunction: (colony:Colony) => colony.name,
|
||||
routerLink: (colony:Colony) => '#',
|
||||
},
|
||||
{
|
||||
header: 'Name2',
|
||||
columnFunction: (colony:Colony) => colony.name,
|
||||
}
|
||||
];
|
||||
|
||||
colonies: Colony[] = [
|
||||
{
|
||||
name: 'Die Römer'
|
||||
},
|
||||
{
|
||||
name: 'Die Griechen'
|
||||
}
|
||||
];
|
||||
|
||||
constructor(public requestService: RequestService) {
|
||||
}
|
||||
}
|
||||
export class HomeComponent {}
|
||||
|
||||
@ -1,60 +1,105 @@
|
||||
|
||||
|
||||
<nav class="bg-skin-accent">
|
||||
<div class="max-w-screen-xl flex flex-wrap items-center justify-between mx-auto p-4">
|
||||
|
||||
<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">
|
||||
<a routerLink="/" 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-4xl font-semibold whitespace-nowrap">Beekeeper</span>
|
||||
<span
|
||||
class="text-skin-primary self-center text-4xl font-semibold whitespace-nowrap"
|
||||
>Bienenkeeper</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-skin-primary" 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
|
||||
type="button"
|
||||
class="block w-10 h-10 text-sm bg-skin-primary rounded-full md:me-0 focus:ring-4 focus:ring-skin-primary"
|
||||
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 uppercase">{{
|
||||
state?.username[0] + state?.roleIdentifier[0]
|
||||
}}</span>
|
||||
</button>
|
||||
<!-- User dropdown -->
|
||||
<div
|
||||
class="z-50 hidden my-4 text-base list-none divide-y divide-skin-primary 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 *ngFor="let usermenuButton of usermenuButtons">
|
||||
<button
|
||||
[routerLink]="
|
||||
usermenuButton.routerLink === undefined
|
||||
? null
|
||||
: [usermenuButton.routerLink]
|
||||
"
|
||||
class="w-full text-left block py-2 px-3 rounded text-skin-primary hover:bg-skin-accent"
|
||||
(click)="clickUserMenuButtonLabel(usermenuButton)"
|
||||
>
|
||||
{{ getUserMenuButtonLabel(usermenuButton) }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!--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">
|
||||
<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
|
||||
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-skin-primary 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="/settings" class="block py-2 px-3 rounded text-skin-primary hover:bg-skin-accent">Einstellungen</a>
|
||||
</li>
|
||||
<li>
|
||||
<button class="w-full block py-2 px-3 rounded text-skin-primary hover:bg-skin-accent" (click)="toggleDarkmode()">{{ darkMode ? 'Hell' : 'Dunkel' }}</button>
|
||||
</li>
|
||||
<li>
|
||||
<button class="w-full block py-2 px-3 rounded text-skin-primary hover:bg-skin-accent" (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 text-xl p-4 md:p-0 mt-4 rounded-lg bg-skin-primary md:bg-skin-accent md:space-x-8 md:flex-row md:mt-0 md:border-0">
|
||||
<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-accent md:p-0">About</a>
|
||||
<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 text-xl p-4 md:p-0 mt-4 rounded-lg bg-skin-primary md:bg-skin-accent md:space-x-8 md:flex-row md:mt-0 md:border-0"
|
||||
>
|
||||
<li *ngFor="let navigationLink of navigationLinks">
|
||||
<a
|
||||
class="block py-2 px-3 rounded text-skin-primary hover:font-bold hover:bg-skin-accent md:p-0"
|
||||
[routerLink]="navigationLink.routerLink"
|
||||
[routerLinkActiveOptions]="{ exact: true }"
|
||||
routerLinkActive="font-bold"
|
||||
>{{ navigationLink.label }}</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@ -1,17 +1,54 @@
|
||||
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';
|
||||
import { AppService } from '../../services/app.service';
|
||||
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";
|
||||
import { AppService } from "../../services/app.service";
|
||||
|
||||
interface NavigationLink {
|
||||
label: string;
|
||||
routerLink: string;
|
||||
}
|
||||
|
||||
interface UserMenuButton {
|
||||
label: Function | string;
|
||||
routerLink: string | undefined;
|
||||
clickCallback: Function | undefined;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-navigation',
|
||||
templateUrl: './navigation.component.html',
|
||||
styleUrls: ['./navigation.component.scss'],
|
||||
selector: "app-navigation",
|
||||
templateUrl: "./navigation.component.html",
|
||||
styleUrls: ["./navigation.component.scss"],
|
||||
})
|
||||
export class NavigationComponent implements OnInit {
|
||||
navigationLinks: NavigationLink[] = [
|
||||
{ routerLink: "/", label: "Startseite" },
|
||||
{ routerLink: "/settings", label: "Völker" },
|
||||
];
|
||||
|
||||
usermenuButtons: UserMenuButton[] = [
|
||||
{
|
||||
label: "Einstellungen",
|
||||
routerLink: "/settings",
|
||||
clickCallback: undefined,
|
||||
},
|
||||
{
|
||||
label: () => (this.darkMode ? "Hell" : "Dunkel"),
|
||||
routerLink: undefined,
|
||||
clickCallback: () => {
|
||||
this.toggleDarkmode();
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Ausloggen",
|
||||
routerLink: undefined,
|
||||
clickCallback: () => {
|
||||
this.logout();
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
state: UserStateResponse | undefined | null;
|
||||
darkMode: boolean;
|
||||
@ -19,14 +56,14 @@ export class NavigationComponent implements OnInit {
|
||||
constructor(
|
||||
private authService: AuthService,
|
||||
private appService: AppService,
|
||||
private router: Router,
|
||||
private router: Router
|
||||
) {
|
||||
this.darkMode = this.appService.darkMode;
|
||||
this.state = this.authService.currentState$.value;
|
||||
this.authService.currentState$.pipe(
|
||||
filter(state => state === undefined)
|
||||
).subscribe( state =>{
|
||||
this.router.navigateByUrl('/auth/login');
|
||||
this.authService.currentState$
|
||||
.pipe(filter((state) => state === undefined))
|
||||
.subscribe((state) => {
|
||||
this.router.navigateByUrl("/auth/login");
|
||||
});
|
||||
}
|
||||
|
||||
@ -42,4 +79,18 @@ export class NavigationComponent implements OnInit {
|
||||
this.appService.toggleDarkMode();
|
||||
this.darkMode = this.appService.darkMode;
|
||||
}
|
||||
|
||||
clickUserMenuButtonLabel(button: UserMenuButton) {
|
||||
if (button.clickCallback !== undefined) {
|
||||
button.clickCallback();
|
||||
}
|
||||
}
|
||||
|
||||
getUserMenuButtonLabel(button: UserMenuButton) {
|
||||
if (typeof button.label === "function") {
|
||||
return button.label();
|
||||
} else {
|
||||
return button.label;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,33 +1,57 @@
|
||||
|
||||
<div>
|
||||
<div class="mb-4 border-b border-gray-200 dark:border-gray-700">
|
||||
<ul class="flex flex-wrap -mb-px text-sm font-medium text-center" id="default-styled-tab" data-tabs-toggle="#default-styled-tab-content" data-tabs-active-classes="text-purple-600 hover:text-purple-600 dark:text-purple-500 dark:hover:text-purple-500 border-purple-600 dark:border-purple-500" data-tabs-inactive-classes="dark:border-transparent text-gray-500 hover:text-gray-600 dark:text-gray-400 border-gray-100 hover:border-gray-300 dark:border-gray-700 dark:hover:text-gray-300" role="tablist">
|
||||
<div class="mb-4 border-b border-skin-primary">
|
||||
<ul
|
||||
class="flex flex-wrap -mb-px text-sm font-medium text-center"
|
||||
id="default-styled-tab"
|
||||
data-tabs-toggle="#default-styled-tab-content"
|
||||
data-tabs-active-classes="text-skin-accent border-skin-accent"
|
||||
data-tabs-inactive-classes="text-skin-primary-muted hover:text-skin-primary border-skin-primary hover:border-skin-accent"
|
||||
role="tablist"
|
||||
>
|
||||
<li class="me-2" role="presentation">
|
||||
<button class="inline-block p-4 border-b-2 rounded-t-lg" id="profile-styled-tab" data-tabs-target="#styled-profile" type="button" role="tab" aria-controls="profile" aria-selected="false">Profile</button>
|
||||
<button
|
||||
class="inline-block p-4 border-b-2 rounded-t-lg"
|
||||
id="profile-styled-tab"
|
||||
data-tabs-target="#styled-profile"
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-controls="profile"
|
||||
aria-selected="false"
|
||||
>
|
||||
Profil
|
||||
</button>
|
||||
</li>
|
||||
<li class="me-2" role="presentation">
|
||||
<button class="inline-block p-4 border-b-2 rounded-t-lg hover:text-gray-600 hover:border-gray-300 dark:hover:text-gray-300" id="dashboard-styled-tab" data-tabs-target="#styled-dashboard" type="button" role="tab" aria-controls="dashboard" aria-selected="false">Dashboard</button>
|
||||
</li>
|
||||
<li class="me-2" role="presentation">
|
||||
<button class="inline-block p-4 border-b-2 rounded-t-lg hover:text-gray-600 hover:border-gray-300 dark:hover:text-gray-300" id="settings-styled-tab" data-tabs-target="#styled-settings" type="button" role="tab" aria-controls="settings" aria-selected="false">Settings</button>
|
||||
</li>
|
||||
<li role="presentation">
|
||||
<button class="inline-block p-4 border-b-2 rounded-t-lg hover:text-gray-600 hover:border-gray-300 dark:hover:text-gray-300" id="contacts-styled-tab" data-tabs-target="#styled-contacts" type="button" role="tab" aria-controls="contacts" aria-selected="false">Contacts</button>
|
||||
<button
|
||||
class="inline-block p-4 border-b-2 rounded-t-lg"
|
||||
id="security-styled-tab"
|
||||
data-tabs-target="#styled-security"
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-controls="security"
|
||||
aria-selected="false"
|
||||
>
|
||||
Sicherheit
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="default-styled-tab-content">
|
||||
<div class="hidden p-4 rounded-lg bg-gray-50 dark:bg-gray-800" id="styled-profile" role="tabpanel" aria-labelledby="profile-tab">
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">This is some placeholder content the <strong class="font-medium text-gray-800 dark:text-white">Profile tab's associated content</strong>. Clicking another tab will toggle the visibility of this one for the next. The tab JavaScript swaps classes to control the content visibility and styling.</p>
|
||||
<div id="default-styled-tab-content" class="text-skin-primary">
|
||||
<div
|
||||
class="hidden p-4 rounded-lg"
|
||||
id="styled-profile"
|
||||
role="tabpanel"
|
||||
aria-labelledby="profile-tab"
|
||||
>
|
||||
<app-tab-profile />
|
||||
</div>
|
||||
<div class="hidden p-4 rounded-lg bg-gray-50 dark:bg-gray-800" id="styled-dashboard" role="tabpanel" aria-labelledby="dashboard-tab">
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">This is some placeholder content the <strong class="font-medium text-gray-800 dark:text-white">Dashboard tab's associated content</strong>. Clicking another tab will toggle the visibility of this one for the next. The tab JavaScript swaps classes to control the content visibility and styling.</p>
|
||||
</div>
|
||||
<div class="hidden p-4 rounded-lg bg-gray-50 dark:bg-gray-800" id="styled-settings" role="tabpanel" aria-labelledby="settings-tab">
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">This is some placeholder content the <strong class="font-medium text-gray-800 dark:text-white">Settings tab's associated content</strong>. Clicking another tab will toggle the visibility of this one for the next. The tab JavaScript swaps classes to control the content visibility and styling.</p>
|
||||
</div>
|
||||
<div class="hidden p-4 rounded-lg bg-gray-50 dark:bg-gray-800" id="styled-contacts" role="tabpanel" aria-labelledby="contacts-tab">
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">This is some placeholder content the <strong class="font-medium text-gray-800 dark:text-white">Contacts tab's associated content</strong>. Clicking another tab will toggle the visibility of this one for the next. The tab JavaScript swaps classes to control the content visibility and styling.</p>
|
||||
<div
|
||||
class="hidden p-4 rounded-lg"
|
||||
id="styled-security"
|
||||
role="tabpanel"
|
||||
aria-labelledby="security-tab"
|
||||
>
|
||||
<app-tab-security />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -1,10 +1,13 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { initFlowbite } from "flowbite";
|
||||
|
||||
@Component({
|
||||
selector: 'app-settings',
|
||||
templateUrl: './settings.component.html',
|
||||
styleUrls: ['./settings.component.scss']
|
||||
selector: "app-settings",
|
||||
templateUrl: "./settings.component.html",
|
||||
styleUrls: ["./settings.component.scss"],
|
||||
})
|
||||
export class SettingsComponent {
|
||||
|
||||
export class SettingsComponent implements OnInit {
|
||||
ngOnInit(): void {
|
||||
initFlowbite();
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
<shared-card
|
||||
icon="/assets/icon.png"
|
||||
header="Test"
|
||||
subHeader="lol noch ein test"
|
||||
>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam ligula erat,
|
||||
auctor eget dolor sed, interdum interdum quam. Donec dui nisl, dignissim quis
|
||||
sollicitudin vitae, eleifend sit amet dui. Cras mattis pretium metus nec
|
||||
venenatis. Nam tempus eros in tempus facilisis. Aliquam sit amet consequat
|
||||
lacus. Mauris lacinia mollis justo eu dapibus. Maecenas vestibulum diam id mi
|
||||
pellentesque accumsan.
|
||||
</shared-card>
|
||||
@ -0,0 +1,10 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-tab-profile',
|
||||
templateUrl: './tab-profile.component.html',
|
||||
styleUrls: ['./tab-profile.component.scss']
|
||||
})
|
||||
export class TabProfileComponent {
|
||||
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
<div class="mb-5">
|
||||
<shared-table [items]="colonies" [columns]="columns"> </shared-table>
|
||||
</div>
|
||||
|
||||
<shared-paginator total="20" perPage="5" />
|
||||
@ -0,0 +1,27 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { ColumnDefinition } from "src/app/shared/components/table/table.component";
|
||||
|
||||
interface Colony {
|
||||
name: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: "app-tab-security",
|
||||
templateUrl: "./tab-security.component.html",
|
||||
styleUrls: ["./tab-security.component.scss"],
|
||||
})
|
||||
export class TabSecurityComponent {
|
||||
columns: ColumnDefinition[] = [
|
||||
{
|
||||
header: "Name",
|
||||
columnFunction: (colony: Colony) => colony.name,
|
||||
routerLink: (colony: Colony) => "#",
|
||||
},
|
||||
{
|
||||
header: "Name2",
|
||||
columnFunction: (colony: Colony) => colony.name,
|
||||
},
|
||||
];
|
||||
|
||||
colonies: Colony[] = [{ name: "Die Römer" }, { name: "Die Griechen" }];
|
||||
}
|
||||
@ -1,20 +1,27 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
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';
|
||||
import { AppService } from './services/app.service';
|
||||
import { SharedModule } from '../shared/shared.module';
|
||||
import { SettingsComponent } from './components/settings/settings.component';
|
||||
import { NgModule } from "@angular/core";
|
||||
import { CommonModule } from "@angular/common";
|
||||
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";
|
||||
import { AppService } from "./services/app.service";
|
||||
import { SharedModule } from "../shared/shared.module";
|
||||
import { SettingsComponent } from "./components/settings/settings.component";
|
||||
import { TabProfileComponent } from "./components/settings/tabs/tab-profile/tab-profile.component";
|
||||
import { TabSecurityComponent } from "./components/settings/tabs/tab-security/tab-security.component";
|
||||
import { RouterModule } from "@angular/router";
|
||||
|
||||
@NgModule({
|
||||
declarations: [NavigationComponent, SettingsComponent],
|
||||
exports: [NavigationComponent, SettingsComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
SharedModule
|
||||
declarations: [
|
||||
NavigationComponent,
|
||||
SettingsComponent,
|
||||
TabProfileComponent,
|
||||
TabSecurityComponent,
|
||||
TabProfileComponent,
|
||||
TabSecurityComponent,
|
||||
],
|
||||
providers: [AuthGuard, AuthService, RequestService, AppService]
|
||||
exports: [NavigationComponent, SettingsComponent],
|
||||
imports: [CommonModule, SharedModule, RouterModule],
|
||||
providers: [AuthGuard, AuthService, RequestService, AppService],
|
||||
})
|
||||
export class CoreModule {}
|
||||
|
||||
@ -1,26 +1,28 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from "@angular/router";
|
||||
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
|
||||
) {
|
||||
}
|
||||
constructor(private authService: AuthService, private router: Router) {}
|
||||
|
||||
canActivate(): Observable<boolean> | boolean {
|
||||
return this.authService.currentState$.pipe(
|
||||
filter(currentState=>currentState!==undefined),
|
||||
filter((currentState) => currentState !== undefined),
|
||||
map((currentState) => {
|
||||
if (currentState === null) {
|
||||
this.router.navigateByUrl('/auth/login');
|
||||
this.router.navigateByUrl("/auth/login");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,14 +1,14 @@
|
||||
export interface ConfirmRegistrationRequest {
|
||||
id: string,
|
||||
password: string,
|
||||
passwordConfirmation: string,
|
||||
id: string;
|
||||
password: string;
|
||||
passwordConfirmation: string;
|
||||
}
|
||||
|
||||
export interface ConfirmRegistrationResponse {
|
||||
id: string,
|
||||
username: string,
|
||||
roleIdentifier: string,
|
||||
createdAt: string,
|
||||
updatedAt: string,
|
||||
permissions: string[]
|
||||
id: string;
|
||||
username: string;
|
||||
roleIdentifier: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
permissions: string[];
|
||||
}
|
||||
@ -1,8 +1,8 @@
|
||||
export interface LoginRequest {
|
||||
identifier: string,
|
||||
password: string,
|
||||
identifier: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export interface LoginResponse {
|
||||
sessionId: string
|
||||
sessionId: string;
|
||||
}
|
||||
@ -1,7 +1,6 @@
|
||||
export interface RegisterUserRequest {
|
||||
mail: string,
|
||||
username: string,
|
||||
mail: string;
|
||||
username: string;
|
||||
}
|
||||
|
||||
export interface RegisterUserResponse {
|
||||
}
|
||||
export interface RegisterUserResponse {}
|
||||
|
||||
@ -1,12 +1,11 @@
|
||||
export interface UserStateRequest {
|
||||
}
|
||||
export interface UserStateRequest {}
|
||||
|
||||
export interface UserStateResponse {
|
||||
id: string,
|
||||
sessionId: string,
|
||||
username: string,
|
||||
roleIdentifier: string,
|
||||
createdAt: string,
|
||||
updatedAt: string,
|
||||
permissions: string[],
|
||||
id: string;
|
||||
sessionId: string;
|
||||
username: string;
|
||||
roleIdentifier: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
permissions: string[];
|
||||
}
|
||||
@ -2,20 +2,20 @@ import { Injectable } from "@angular/core";
|
||||
|
||||
@Injectable()
|
||||
export class AppService {
|
||||
|
||||
darkMode: boolean;
|
||||
|
||||
constructor(
|
||||
) {
|
||||
this.darkMode = (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches);
|
||||
constructor() {
|
||||
this.darkMode =
|
||||
window.matchMedia &&
|
||||
window.matchMedia("(prefers-color-scheme: dark)").matches;
|
||||
this.applyDarkMode();
|
||||
}
|
||||
|
||||
private applyDarkMode(): void {
|
||||
if (this.darkMode) {
|
||||
document.documentElement.classList.add('theme-dark');
|
||||
document.documentElement.classList.add("theme-dark");
|
||||
} else {
|
||||
document.documentElement.classList.remove('theme-dark');
|
||||
document.documentElement.classList.remove("theme-dark");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -4,39 +4,42 @@ import { UserStateResponse } from "../models/user-state-request.model";
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
import { LoginRequest, LoginResponse } from "../models/login-request.model";
|
||||
import { Router } from "@angular/router";
|
||||
import { RegisterUserRequest, RegisterUserResponse } from "../models/register-user-request.model";
|
||||
import { ConfirmRegistrationRequest, ConfirmRegistrationResponse } from "../models/confirm-registration-request.model";
|
||||
import {
|
||||
RegisterUserRequest,
|
||||
RegisterUserResponse,
|
||||
} from "../models/register-user-request.model";
|
||||
import {
|
||||
ConfirmRegistrationRequest,
|
||||
ConfirmRegistrationResponse,
|
||||
} from "../models/confirm-registration-request.model";
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
currentState$ = new BehaviorSubject<UserStateResponse | null | undefined>(
|
||||
undefined
|
||||
);
|
||||
|
||||
currentState$ = new BehaviorSubject<UserStateResponse | null | undefined>(undefined);
|
||||
|
||||
constructor(
|
||||
private requestService: RequestService,
|
||||
private router: Router
|
||||
) {
|
||||
}
|
||||
constructor(private requestService: RequestService, private router: Router) {}
|
||||
|
||||
readUserState(): void {
|
||||
this.requestService.get(
|
||||
'user/state',
|
||||
"user/state",
|
||||
{},
|
||||
(response: UserStateResponse) => {
|
||||
console.log('set next state');
|
||||
console.log("set next state");
|
||||
this.currentState$.next(response);
|
||||
},
|
||||
() => {
|
||||
this.currentState$.next(null);
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
login(body: LoginRequest): LoginResponse | null {
|
||||
let result = null;
|
||||
|
||||
this.requestService.post(
|
||||
'auth/login-user',
|
||||
"auth/login-user",
|
||||
body,
|
||||
(response: LoginResponse) => {
|
||||
result = response;
|
||||
@ -51,7 +54,7 @@ export class AuthService {
|
||||
let result = null;
|
||||
|
||||
this.requestService.post(
|
||||
'auth/register-user',
|
||||
"auth/register-user",
|
||||
body,
|
||||
(response: LoginResponse) => {
|
||||
result = response;
|
||||
@ -62,11 +65,13 @@ export class AuthService {
|
||||
return result;
|
||||
}
|
||||
|
||||
confirmRegistration(body: ConfirmRegistrationRequest): ConfirmRegistrationResponse|null {
|
||||
confirmRegistration(
|
||||
body: ConfirmRegistrationRequest
|
||||
): ConfirmRegistrationResponse | null {
|
||||
let result = null;
|
||||
|
||||
this.requestService.post(
|
||||
'auth/confirm-registration',
|
||||
"auth/confirm-registration",
|
||||
body,
|
||||
(response: LoginResponse) => {
|
||||
result = response;
|
||||
@ -78,13 +83,9 @@ export class AuthService {
|
||||
}
|
||||
|
||||
logout(): void {
|
||||
this.requestService.post(
|
||||
'auth/logout-user',
|
||||
{},
|
||||
(response: any) => {
|
||||
this.requestService.post("auth/logout-user", {}, (response: any) => {
|
||||
this.currentState$.next(undefined);
|
||||
this.readUserState();
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1,59 +1,63 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Router } from '@angular/router';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient } from "@angular/common/http";
|
||||
import { Router } from "@angular/router";
|
||||
import { Injectable } from "@angular/core";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
providedIn: "root",
|
||||
})
|
||||
export class RequestService {
|
||||
constructor(private http: HttpClient, private router: Router) {}
|
||||
|
||||
constructor(
|
||||
private http: HttpClient,
|
||||
private router: Router,
|
||||
public post(
|
||||
apiPath: string,
|
||||
body: any,
|
||||
successFunction: Function,
|
||||
errorFunction: Function | null = null
|
||||
) {
|
||||
}
|
||||
|
||||
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) => {
|
||||
successFunction(answer);
|
||||
},
|
||||
(error: any) => {
|
||||
if (errorFunction === null)
|
||||
this.handleError(error);
|
||||
else
|
||||
errorFunction(error);
|
||||
if (errorFunction === null) this.handleError(error);
|
||||
else errorFunction(error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public get(apiPath: string, body: any, successFunction: Function, errorFunction: Function|null = null)
|
||||
{
|
||||
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);
|
||||
if (errorFunction === null) this.handleError(error);
|
||||
else errorFunction(error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public postFiles(apiPath: string, files: File[], successFunction: Function, errorFunction: Function|null = null) {
|
||||
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';
|
||||
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]);
|
||||
formData.append("file" + fileIndex, files[fileIndex]);
|
||||
}
|
||||
|
||||
let url = this.obtainUrl(apiPath);
|
||||
@ -62,10 +66,8 @@ export class RequestService {
|
||||
successFunction(answer);
|
||||
},
|
||||
(error: any) => {
|
||||
if (errorFunction === null)
|
||||
this.handleError(error);
|
||||
else
|
||||
errorFunction(error);
|
||||
if (errorFunction === null) this.handleError(error);
|
||||
else errorFunction(error);
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -73,34 +75,33 @@ export class RequestService {
|
||||
private obtainUrl(apiPath: string): string {
|
||||
let hostString = window.location.host;
|
||||
let protocol = window.location.protocol;
|
||||
return protocol + '//' + hostString + '/api/' + apiPath;
|
||||
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']);
|
||||
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');
|
||||
this.showSnackBar("Du bist nicht für diese Aktion autorisiert", "Ok");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
let errorObject = answer.error.error;
|
||||
|
||||
if (errorObject.hasOwnProperty('message')) {
|
||||
if (errorObject.hasOwnProperty("message")) {
|
||||
throw errorObject.message.toString();
|
||||
}
|
||||
|
||||
if (errorObject.hasOwnProperty('code')) {
|
||||
if (errorObject.hasOwnProperty("code")) {
|
||||
throw errorObject.code.toString();
|
||||
}
|
||||
} catch (error: any) {
|
||||
this.showSnackBar(error.toString(), 'Ok');
|
||||
this.showSnackBar(error.toString(), "Ok");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2,7 +2,11 @@
|
||||
id="card"
|
||||
class="grow p-3 my-2 rounded-xl shadow-sm shadow-skin-primary border border-skin-primary divide-y divide-skin-primary"
|
||||
>
|
||||
<div *ngIf="icon !== null || header !== null || subHeader !== null" id="header" class="mb-5">
|
||||
<div
|
||||
*ngIf="icon !== null || header !== null || subHeader !== null"
|
||||
id="header"
|
||||
class="mb-5"
|
||||
>
|
||||
<div class="w-full flex flex-row">
|
||||
<!--Icon-->
|
||||
<div *ngIf="icon !== null" class="basis-auto">
|
||||
@ -13,12 +17,11 @@
|
||||
<div class="basis-full truncate">
|
||||
<div
|
||||
*ngIf="header !== null"
|
||||
class="text-xl font-medium text-skin-primary mb-2">
|
||||
class="text-xl font-medium text-skin-primary mb-2"
|
||||
>
|
||||
{{ header }}
|
||||
</div>
|
||||
<div
|
||||
*ngIf="subHeader !== null"
|
||||
class="text-skin-primary-muted pl-2">
|
||||
<div *ngIf="subHeader !== null" class="text-skin-primary-muted pl-2">
|
||||
{{ subHeader }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { Component, Input } from "@angular/core";
|
||||
|
||||
@Component({
|
||||
selector: 'shared-card',
|
||||
templateUrl: './card.component.html',
|
||||
styleUrls: ['./card.component.scss'],
|
||||
selector: "shared-card",
|
||||
templateUrl: "./card.component.html",
|
||||
styleUrls: ["./card.component.scss"],
|
||||
})
|
||||
export class CardComponent {
|
||||
@Input() header: string | null = null;
|
||||
|
||||
@ -28,9 +28,9 @@
|
||||
<div
|
||||
class="flex items-center justify-center h-8 leading-tight border border-skin-primary text-skin-primary"
|
||||
[ngClass]="{
|
||||
'bg-skin-accent font-bold text-skin-secondary hover:text-skin-primary': item.page === page,
|
||||
'bg-skin-secondary':
|
||||
item.page !== page
|
||||
'bg-skin-accent font-bold text-skin-secondary hover:text-skin-primary':
|
||||
item.page === page,
|
||||
'bg-skin-secondary': item.page !== page
|
||||
}"
|
||||
>
|
||||
<div *ngIf="item.page === null" class="px-3">...</div>
|
||||
|
||||
@ -5,16 +5,16 @@ import {
|
||||
OnChanges,
|
||||
Output,
|
||||
SimpleChanges,
|
||||
} from '@angular/core';
|
||||
} from "@angular/core";
|
||||
|
||||
export interface PaginatorItem {
|
||||
page: number | null;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'shared-paginator',
|
||||
templateUrl: './paginator.component.html',
|
||||
styleUrls: ['./paginator.component.scss'],
|
||||
selector: "shared-paginator",
|
||||
templateUrl: "./paginator.component.html",
|
||||
styleUrls: ["./paginator.component.scss"],
|
||||
})
|
||||
export class PaginatorComponent implements OnChanges {
|
||||
@Output() pageChange = new EventEmitter<number>();
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { Component, Input } from "@angular/core";
|
||||
|
||||
export interface ColumnDefinition {
|
||||
header: string;
|
||||
@ -8,9 +8,9 @@ export interface ColumnDefinition {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'shared-table',
|
||||
templateUrl: './table.component.html',
|
||||
styleUrls: ['./table.component.scss'],
|
||||
selector: "shared-table",
|
||||
templateUrl: "./table.component.html",
|
||||
styleUrls: ["./table.component.scss"],
|
||||
})
|
||||
export class TableComponent {
|
||||
@Input() items: any[] = [];
|
||||
@ -18,6 +18,6 @@ export class TableComponent {
|
||||
|
||||
isBoolean(obje: any): boolean {
|
||||
console.log(obje);
|
||||
return typeof obje === 'boolean';
|
||||
return typeof obje === "boolean";
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +0,0 @@
|
||||
export interface TabItem {
|
||||
id: string;
|
||||
title: string;
|
||||
}
|
||||
4
src/app/shared/models/tab-item.model.ts
Normal file
4
src/app/shared/models/tab-item.model.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export interface TabItem {
|
||||
id: string;
|
||||
title: string;
|
||||
}
|
||||
@ -1,28 +1,14 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CardComponent } from './components/card/card.component';
|
||||
import { PaginatorComponent } from './components/paginator/paginator.component';
|
||||
import { TableComponent } from './components/table/table.component';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { NgModule } from "@angular/core";
|
||||
import { RouterModule } from "@angular/router";
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { CardComponent } from "./components/card/card.component";
|
||||
import { PaginatorComponent } from "./components/paginator/paginator.component";
|
||||
import { TableComponent } from "./components/table/table.component";
|
||||
import { FormsModule } from "@angular/forms";
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
CardComponent,
|
||||
PaginatorComponent,
|
||||
TableComponent,
|
||||
],
|
||||
exports: [
|
||||
CardComponent,
|
||||
PaginatorComponent,
|
||||
TableComponent,
|
||||
|
||||
FormsModule,
|
||||
],
|
||||
imports: [
|
||||
RouterModule,
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
],
|
||||
declarations: [CardComponent, PaginatorComponent, TableComponent],
|
||||
exports: [CardComponent, PaginatorComponent, TableComponent, FormsModule],
|
||||
imports: [RouterModule, CommonModule, FormsModule],
|
||||
})
|
||||
export class SharedModule {}
|
||||
|
||||
10
src/main.ts
10
src/main.ts
@ -1,7 +1,7 @@
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
import { AppModule } from "./app/app.module";
|
||||
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||
.catch(err => console.error(err));
|
||||
platformBrowserDynamic()
|
||||
.bootstrapModule(AppModule)
|
||||
.catch((err) => console.error(err));
|
||||
|
||||
@ -28,4 +28,3 @@
|
||||
--color-accent: 250, 183, 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,61 +1,56 @@
|
||||
function withOpacity(variableName) {
|
||||
return ({ opacityValue }) => {
|
||||
if (opacityValue !== undefined) {
|
||||
return `rgba(var(${variableName}), ${opacityValue})`
|
||||
}
|
||||
return `rgb(var(${variableName}))`
|
||||
return `rgba(var(${variableName}), ${opacityValue})`;
|
||||
}
|
||||
return `rgb(var(${variableName}))`;
|
||||
};
|
||||
}
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: [
|
||||
"./src/**/*.{html,ts}",
|
||||
"./node_modules/flowbite/**/*.js"
|
||||
],
|
||||
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'),
|
||||
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'),
|
||||
primary: withOpacity("--color-primary"),
|
||||
secondary: withOpacity("--color-secondary"),
|
||||
accent: withOpacity("--color-accent"),
|
||||
},
|
||||
},
|
||||
boxShadowColor: {
|
||||
skin: {
|
||||
primary: withOpacity('--color-text-secondary-muted'),
|
||||
}
|
||||
primary: withOpacity("--color-text-secondary-muted"),
|
||||
},
|
||||
},
|
||||
ringColor: {
|
||||
skin: {
|
||||
primary: withOpacity('--color-text-secondary-muted'),
|
||||
}
|
||||
primary: withOpacity("--color-text-secondary-muted"),
|
||||
},
|
||||
},
|
||||
divideColor: {
|
||||
skin: {
|
||||
primary: withOpacity('--color-text-secondary-muted'),
|
||||
}
|
||||
primary: withOpacity("--color-text-secondary-muted"),
|
||||
},
|
||||
},
|
||||
borderColor: {
|
||||
skin: {
|
||||
primary: withOpacity('--color-text-secondary-muted'),
|
||||
}
|
||||
}
|
||||
primary: withOpacity("--color-text-secondary-muted"),
|
||||
accent: withOpacity("--color-text-accent-muted"),
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
require('flowbite/plugin')
|
||||
],
|
||||
}
|
||||
|
||||
},
|
||||
},
|
||||
plugins: [require("flowbite/plugin")],
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user