Compare commits
No commits in common. "b7f73033f3039df3f6dc03c2194e5536a36b2ed9" and "5fa704cd964bcb8e1b9298a643bf5ffe38abcbae" have entirely different histories.
b7f73033f3
...
5fa704cd96
|
@ -29,7 +29,6 @@
|
||||||
"@angular/platform-browser-dynamic": "^17.3.0",
|
"@angular/platform-browser-dynamic": "^17.3.0",
|
||||||
"@angular/router": "^17.3.0",
|
"@angular/router": "^17.3.0",
|
||||||
"@types/dompurify": "^3.0.5",
|
"@types/dompurify": "^3.0.5",
|
||||||
"chroma-js": "^2.4.2",
|
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"dompurify": "^3.1.3",
|
"dompurify": "^3.1.3",
|
||||||
"primeicons": "^7.0.0",
|
"primeicons": "^7.0.0",
|
||||||
|
@ -47,14 +46,11 @@
|
||||||
"@angular-eslint/template-parser": "17.2.1",
|
"@angular-eslint/template-parser": "17.2.1",
|
||||||
"@angular/cli": "^17.3.0",
|
"@angular/cli": "^17.3.0",
|
||||||
"@angular/compiler-cli": "^17.3.0",
|
"@angular/compiler-cli": "^17.3.0",
|
||||||
"@types/chroma-js": "^2.4.4",
|
|
||||||
"@types/crypto-js": "^4.2.2",
|
"@types/crypto-js": "^4.2.2",
|
||||||
"@types/jest": "^29.5.12",
|
"@types/jest": "^29.5.12",
|
||||||
"@typescript-eslint/eslint-plugin": "6.19.0",
|
"@typescript-eslint/eslint-plugin": "6.19.0",
|
||||||
"@typescript-eslint/parser": "6.19.0",
|
"@typescript-eslint/parser": "6.19.0",
|
||||||
"autoprefixer": "^10.4.19",
|
|
||||||
"concurrently": "^8.2.2",
|
"concurrently": "^8.2.2",
|
||||||
"daisyui": "^4.12.2",
|
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-import": "^2.29.1",
|
"eslint-plugin-import": "^2.29.1",
|
||||||
|
@ -63,10 +59,7 @@
|
||||||
"eslint-plugin-unused-imports": "^3.2.0",
|
"eslint-plugin-unused-imports": "^3.2.0",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"jest-preset-angular": "^14.0.3",
|
"jest-preset-angular": "^14.0.3",
|
||||||
"postcss": "^8.4.38",
|
|
||||||
"prettier": "3.2.5",
|
"prettier": "3.2.5",
|
||||||
"tailwindcss": "^3.4.4",
|
|
||||||
"tailwindcss-animated": "^1.1.2",
|
|
||||||
"typescript": "~5.4.2",
|
"typescript": "~5.4.2",
|
||||||
"wait-on": "^7.2.0"
|
"wait-on": "^7.2.0"
|
||||||
},
|
},
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
plugins: {
|
|
||||||
tailwindcss: {},
|
|
||||||
autoprefixer: {},
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +1,6 @@
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { RouterOutlet } from '@angular/router';
|
import { RouterOutlet } from '@angular/router';
|
||||||
|
|
||||||
import { ThemeService } from './shared/service';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
|
@ -12,5 +10,5 @@ import { ThemeService } from './shared/service';
|
||||||
styleUrl: './app.component.scss',
|
styleUrl: './app.component.scss',
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent {
|
||||||
public constructor(private readonly themeService: ThemeService) {}
|
public constructor() {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ const publicRoutes: Routes = [
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'welcome',
|
path: 'signup',
|
||||||
loadComponent: () =>
|
loadComponent: () =>
|
||||||
import('./pages/register-root/register-root.component').then(
|
import('./pages/register-root/register-root.component').then(
|
||||||
(m) => m.RegisterRootComponent
|
(m) => m.RegisterRootComponent
|
||||||
|
|
|
@ -1,39 +1,20 @@
|
||||||
<div class="bg-primary w-screen h-screen">
|
<div id="background">
|
||||||
<div class="modal modal-open">
|
<div class="wrapper">
|
||||||
<div
|
<div class="content">
|
||||||
[ngStyle]="backgroundStyle"
|
@if (verifyStatus() === true) {
|
||||||
class="modal-box w-11/12 h-2/6 max-w-5xl flex">
|
@if (showRedirectMessage()) {
|
||||||
<div class="w-full flex flex-col justify-center items-center">
|
<h1>Es geht gleich los!</h1>
|
||||||
@if (verifyStatus() === true) {
|
<h2>
|
||||||
@if (showRedirectMessage()) {
|
Danke für das bestätigen der E-Mail - Wir leiten dich zum Login
|
||||||
<div class="text-center">
|
weiter!
|
||||||
<h1 class="font-bold text-3xl pt-5">Your email is verified!</h1>
|
</h2>
|
||||||
<p class="pt-3 pb-6">
|
|
||||||
Your email {{ email() }} has been successfully verified. will
|
|
||||||
<br />
|
|
||||||
You will be automatically redirected in to the login page to
|
|
||||||
access the application shortly.
|
|
||||||
</p>
|
|
||||||
<button
|
|
||||||
(click)="navigateToWelcomeScreen()"
|
|
||||||
class="btn btn-primary no-animation">
|
|
||||||
Go to the App
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
} @else if (verifyStatus() === false) {
|
|
||||||
<div class="text-center">
|
|
||||||
<h1 class="font-bold text-3xl pt-5">
|
|
||||||
Oops, something went wrong! :(
|
|
||||||
</h1>
|
|
||||||
<p class="pt-3">We couldn't verify your email.</p>
|
|
||||||
</div>
|
|
||||||
} @else {
|
|
||||||
<div class="text-center">
|
|
||||||
<span class="loading loading-dots loading-lg"></span>
|
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
</div>
|
} @else if (verifyStatus() === false) {
|
||||||
|
<h1>Oops, da ist etwas schief gelaufen!</h1>
|
||||||
|
<h2>Der Link ist nicht mehr gültig</h2>
|
||||||
|
} @else {
|
||||||
|
<h1>Verifizierung wird durchgeführt...</h1>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
#background {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
flex: 1;
|
||||||
|
background-color: lightsalmon;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.content{
|
||||||
|
flex-direction: column;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: center;
|
||||||
|
h1 {
|
||||||
|
font-size: 4rem;
|
||||||
|
margin-left: 3rem;
|
||||||
|
line-height: 1rem;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
margin-left: 3rem;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
margin-left: 3rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,6 @@
|
||||||
import { CommonModule } from '@angular/common';
|
|
||||||
import {
|
import {
|
||||||
ChangeDetectionStrategy,
|
ChangeDetectionStrategy,
|
||||||
Component,
|
Component,
|
||||||
ElementRef,
|
|
||||||
InputSignal,
|
InputSignal,
|
||||||
OnInit,
|
OnInit,
|
||||||
WritableSignal,
|
WritableSignal,
|
||||||
|
@ -14,12 +12,11 @@ import { Router } from '@angular/router';
|
||||||
import { delay, filter, tap } from 'rxjs';
|
import { delay, filter, tap } from 'rxjs';
|
||||||
|
|
||||||
import { VerifyApiService } from '../../api';
|
import { VerifyApiService } from '../../api';
|
||||||
import { BackgroundPatternService, ThemeService } from '../../shared/service';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-email-verify-root',
|
selector: 'app-email-verify-root',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [CommonModule],
|
imports: [],
|
||||||
providers: [],
|
providers: [],
|
||||||
templateUrl: './email-verify-root.component.html',
|
templateUrl: './email-verify-root.component.html',
|
||||||
styleUrl: './email-verify-root.component.scss',
|
styleUrl: './email-verify-root.component.scss',
|
||||||
|
@ -27,8 +24,6 @@ import { BackgroundPatternService, ThemeService } from '../../shared/service';
|
||||||
})
|
})
|
||||||
export class EmailVerifyRootComponent implements OnInit {
|
export class EmailVerifyRootComponent implements OnInit {
|
||||||
public token: InputSignal<string> = input<string>('');
|
public token: InputSignal<string> = input<string>('');
|
||||||
public email: WritableSignal<string> = signal<string>('');
|
|
||||||
public backgroundStyle: { 'background-image': string } | null = null;
|
|
||||||
public verifyStatus: WritableSignal<boolean | null> = signal<boolean | null>(
|
public verifyStatus: WritableSignal<boolean | null> = signal<boolean | null>(
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
@ -36,71 +31,19 @@ export class EmailVerifyRootComponent implements OnInit {
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
private readonly api: VerifyApiService,
|
private readonly api: VerifyApiService,
|
||||||
private readonly router: Router,
|
private readonly router: Router
|
||||||
private readonly el: ElementRef,
|
|
||||||
private readonly backgroundPatternService: BackgroundPatternService,
|
|
||||||
private readonly themeService: ThemeService
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public ngOnInit(): void {
|
public ngOnInit(): void {
|
||||||
this.verifyEmail();
|
this.verifyEmail();
|
||||||
this.setBackground();
|
|
||||||
}
|
|
||||||
|
|
||||||
public setBackground(): void {
|
|
||||||
const theme = this.themeService.getTheme();
|
|
||||||
let opacity: number;
|
|
||||||
|
|
||||||
if (theme === 'dark') {
|
|
||||||
opacity = 0.05;
|
|
||||||
} else {
|
|
||||||
opacity = 0.1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const colorPrimary = getComputedStyle(
|
|
||||||
this.el.nativeElement
|
|
||||||
).getPropertyValue('--p');
|
|
||||||
|
|
||||||
const svgUrl = this.backgroundPatternService.getWigglePattern(
|
|
||||||
colorPrimary,
|
|
||||||
opacity
|
|
||||||
);
|
|
||||||
|
|
||||||
this.backgroundStyle = { 'background-image': `url("${svgUrl}")` };
|
|
||||||
}
|
|
||||||
|
|
||||||
public navigateToWelcomeScreen(): void {
|
|
||||||
const email: string = this.extractEmail();
|
|
||||||
|
|
||||||
this.router.navigate(['/welcome'], {
|
|
||||||
queryParams: { verified: true, email: email },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private extractVerifyToken(): string {
|
|
||||||
const [verifyToken]: string[] = this.token().split('|');
|
|
||||||
|
|
||||||
return verifyToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
private extractEmail(): string {
|
|
||||||
const [, email]: string[] = this.token().split('|');
|
|
||||||
|
|
||||||
return email;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private verifyEmail(): void {
|
private verifyEmail(): void {
|
||||||
const verifyToken: string = this.extractVerifyToken();
|
const [verifyToken, email]: string[] = this.token().split('|');
|
||||||
const email: string = this.extractEmail();
|
|
||||||
|
|
||||||
if (verifyToken && email) {
|
|
||||||
this.email.set(decodeURIComponent(atob(email)));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.api
|
this.api
|
||||||
.verifyControllerVerifyEmail(verifyToken)
|
.verifyControllerVerifyEmail(verifyToken)
|
||||||
.pipe(
|
.pipe(
|
||||||
delay(1500),
|
|
||||||
tap((isVerified: boolean) => {
|
tap((isVerified: boolean) => {
|
||||||
this.verifyStatus.set(isVerified);
|
this.verifyStatus.set(isVerified);
|
||||||
}),
|
}),
|
||||||
|
@ -108,10 +51,12 @@ export class EmailVerifyRootComponent implements OnInit {
|
||||||
tap(() => {
|
tap(() => {
|
||||||
this.showRedirectMessage.set(true);
|
this.showRedirectMessage.set(true);
|
||||||
}),
|
}),
|
||||||
delay(10000)
|
delay(5000)
|
||||||
)
|
)
|
||||||
.subscribe(() => {
|
.subscribe(() => {
|
||||||
this.navigateToWelcomeScreen();
|
this.router.navigate(['/signup'], {
|
||||||
|
queryParams: { verified: true, email: email },
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ export class HomeComponent implements OnInit {
|
||||||
},
|
},
|
||||||
(error: HttpErrorResponse) => {
|
(error: HttpErrorResponse) => {
|
||||||
if (error.status === 401) {
|
if (error.status === 401) {
|
||||||
this.router.navigate(['welcome'], {
|
this.router.navigate(['signup'], {
|
||||||
queryParams: { login: true },
|
queryParams: { login: true },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,301 +1,110 @@
|
||||||
@if (!userSignupSuccess()) {
|
<div id="background">
|
||||||
<div class="flex h-screen w-screen">
|
<div class="img-zone">
|
||||||
<div
|
<div class="img-wrapper">
|
||||||
[ngStyle]="leftBackgroundStyle"
|
@if (userSignupSuccess()) {
|
||||||
class="hidden md:flex md:flex-col md:w-1/2 bg-primary">
|
<div class="success">
|
||||||
<div class="flex-1 flex items-start pt-16 px-12">
|
<h1>Danke für deine Registrierung!</h1>
|
||||||
<h1 class="text-3xl text-base-100">[LOGO] APP-NAME</h1>
|
<h2>
|
||||||
</div>
|
Wir haben dir eine Mail geschickt an
|
||||||
<div class="flex-1 flex flex-col justify-end pb-16 px-12">
|
{{ form?.get('email')?.value }}. Bitte bestätige deine
|
||||||
<blockquote>
|
E-Mail-Adresse um fortzufahren.
|
||||||
<p class="text-xl text-base-100 font-semibold">
|
</h2>
|
||||||
“This library has saved me countless hours of work and helped me
|
<p>Du kannst diesen Tab nun schließen</p>
|
||||||
deliver stunning designs to my clients faster than ever before.”
|
|
||||||
</p>
|
|
||||||
<small class="block text-sm font-light text-base-100 mt-4">
|
|
||||||
— Sofia Davis
|
|
||||||
</small>
|
|
||||||
</blockquote>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Rechter Bereich, immer sichtbar -->
|
|
||||||
<div [ngStyle]="rightBackgroundStyle" class="flex flex-col w-full md:w-1/2">
|
|
||||||
<div class="flex px-12 gap-3">
|
|
||||||
<div class="flex items-start justify-end pt-16">
|
|
||||||
<label class="swap swap-rotate">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
(change)="toggleTheme()"
|
|
||||||
[checked]="isDarkMode" />
|
|
||||||
|
|
||||||
<!-- sun icon -->
|
|
||||||
<svg
|
|
||||||
class="swap-on h-10 w-10 fill-current"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 24 24">
|
|
||||||
<path
|
|
||||||
d="M5.64,17l-.71.71a1,1,0,0,0,0,1.41,1,1,0,0,0,1.41,0l.71-.71A1,1,0,0,0,5.64,17ZM5,12a1,1,0,0,0-1-1H3a1,1,0,0,0,0,2H4A1,1,0,0,0,5,12Zm7-7a1,1,0,0,0,1-1V3a1,1,0,0,0-2,0V4A1,1,0,0,0,12,5ZM5.64,7.05a1,1,0,0,0,.7.29,1,1,0,0,0,.71-.29,1,1,0,0,0,0-1.41l-.71-.71A1,1,0,0,0,4.93,6.34Zm12,.29a1,1,0,0,0,.7-.29l.71-.71a1,1,0,1,0-1.41-1.41L17,5.64a1,1,0,0,0,0,1.41A1,1,0,0,0,17.66,7.34ZM21,11H20a1,1,0,0,0,0,2h1a1,1,0,0,0,0-2Zm-9,8a1,1,0,0,0-1,1v1a1,1,0,0,0,2,0V20A1,1,0,0,0,12,19ZM18.36,17A1,1,0,0,0,17,18.36l.71.71a1,1,0,0,0,1.41,0,1,1,0,0,0,0-1.41ZM12,6.5A5.5,5.5,0,1,0,17.5,12,5.51,5.51,0,0,0,12,6.5Zm0,9A3.5,3.5,0,1,1,15.5,12,3.5,3.5,0,0,1,12,15.5Z" />
|
|
||||||
</svg>
|
|
||||||
|
|
||||||
<!-- moon icon -->
|
|
||||||
<svg
|
|
||||||
class="swap-off h-10 w-10 fill-current"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 24 24">
|
|
||||||
<path
|
|
||||||
d="M21.64,13a1,1,0,0,0-1.05-.14,8.05,8.05,0,0,1-3.37.73A8.15,8.15,0,0,1,9.08,5.49a8.59,8.59,0,0,1,.25-2A1,1,0,0,0,8,2.36,10.14,10.14,0,1,0,22,14.05,1,1,0,0,0,21.64,13Zm-9.5,6.69A8.14,8.14,0,0,1,7.08,5.22v.27A10.15,10.15,0,0,0,17.22,15.63a9.79,9.79,0,0,0,2.1-.22A8.11,8.11,0,0,1,12.14,19.73Z" />
|
|
||||||
</svg>
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-1 items-start flex justify-end pt-16">
|
} @else {
|
||||||
@if (isSignupSignal()) {
|
<div class="headline">
|
||||||
<button
|
<h1>Hi, Welcome to Ticket App.</h1>
|
||||||
(click)="toggleAction('signin')"
|
|
||||||
class="btn btn-primary btn-outline no-animation">
|
|
||||||
Login
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
@if (isSigninSignal()) {
|
|
||||||
@if (displaySkeleton()) {
|
|
||||||
<div class="skeleton w-36 h-12"></div>
|
|
||||||
} @else {
|
|
||||||
<button
|
|
||||||
(click)="toggleAction('signup')"
|
|
||||||
class="btn btn-primary btn-outline no-animation">
|
|
||||||
New here - Register now!
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@if (isSignupSignal()) {
|
|
||||||
<div
|
|
||||||
class="animate-fade-down animate-once animate-duration-1000 animate-ease-in-out flex-1 flex flex-col justify-center items-center px-12">
|
|
||||||
<h1 class="text-3xl font-semibold text-center">Create an Account</h1>
|
|
||||||
<p class="text-center">
|
|
||||||
Enter your email below to create your Account
|
|
||||||
</p>
|
|
||||||
<form
|
|
||||||
[formGroup]="form"
|
|
||||||
(ngSubmit)="onSubmit()"
|
|
||||||
class="flex gap-4 flex-col items-center py-6 w-full max-w-md">
|
|
||||||
<div class="form-control w-full">
|
|
||||||
<label
|
|
||||||
[ngClass]="{
|
|
||||||
'w-full': true,
|
|
||||||
'border-error focus:border-error':
|
|
||||||
form.get('email')?.invalid &&
|
|
||||||
(form.get('email')?.dirty || form.get('email')?.touched)
|
|
||||||
}"
|
|
||||||
class="input input-bordered flex items-center gap-2">
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 16 16"
|
|
||||||
fill="currentColor"
|
|
||||||
class="h-4 w-4 opacity-70">
|
|
||||||
<path
|
|
||||||
d="M2.5 3A1.5 1.5 0 0 0 1 4.5v.793c.026.009.051.02.076.032L7.674 8.51c.206.1.446.1.652 0l6.598-3.185A.755.755 0 0 1 15 5.293V4.5A1.5 1.5 0 0 0 13.5 3h-11Z" />
|
|
||||||
<path
|
|
||||||
d="M15 6.954 8.978 9.86a2.25 2.25 0 0 1-1.956 0L1 6.954V11.5A1.5 1.5 0 0 0 2.5 13h11a1.5 1.5 0 0 0 1.5-1.5V6.954Z" />
|
|
||||||
</svg>
|
|
||||||
<input
|
|
||||||
formControlName="email"
|
|
||||||
type="text"
|
|
||||||
class="grow"
|
|
||||||
placeholder="name@example.com" />
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-control w-full">
|
|
||||||
<label
|
|
||||||
[ngClass]="{
|
|
||||||
'w-full': true,
|
|
||||||
'border-error focus:border-error':
|
|
||||||
form.get('password')?.invalid &&
|
|
||||||
(form.get('password')?.dirty ||
|
|
||||||
form.get('password')?.touched)
|
|
||||||
}"
|
|
||||||
class="input input-bordered flex items-center gap-2">
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 16 16"
|
|
||||||
fill="currentColor"
|
|
||||||
class="h-4 w-4 opacity-70">
|
|
||||||
<path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M14 6a4 4 0 0 1-4.899 3.899l-1.955 1.955a.5.5 0 0 1-.353.146H5v1.5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1-.5-.5v-2.293a.5.5 0 0 1 .146-.353l3.955-3.955A4 4 0 1 1 14 6Zm-4-2a.75.75 0 0 0 0 1.5.5.5 0 0 1 .5.5.75.75 0 0 0 1.5 0 2 2 0 0 0-2-2Z"
|
|
||||||
clip-rule="evenodd" />
|
|
||||||
</svg>
|
|
||||||
<input
|
|
||||||
formControlName="password"
|
|
||||||
type="password"
|
|
||||||
class="grow"
|
|
||||||
value="" />
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<button class="btn w-full btn-primary font-semibold">
|
|
||||||
@if (isLoading()) {
|
|
||||||
<span class="loading loading-spinner"></span>
|
|
||||||
}
|
|
||||||
Sign Up with Email
|
|
||||||
</button>
|
|
||||||
<p class="text-xs w-full text-center">
|
|
||||||
By clicking continue, you agree to our
|
|
||||||
<u class="cursor-pointer">Terms of Service</u>
|
|
||||||
and
|
|
||||||
<u class="cursor-pointer">Privacy Policy</u>
|
|
||||||
.
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@if (isSigninSignal()) {
|
</div>
|
||||||
<div
|
</div>
|
||||||
class="animate-fade-down animate-once animate-duration-1000 animate-ease-in-out flex-1 flex flex-col justify-center items-center px-12">
|
|
||||||
@if (displaySkeleton()) {
|
@if (!userSignupSuccess()) {
|
||||||
<div class="flex items-center w-full flex-col max-w-md gap-4">
|
<div class="content-zone">
|
||||||
<div class="skeleton w-36 h-10"></div>
|
<h1>
|
||||||
<div class="skeleton w-full h-10 max-w-md"></div>
|
@if (isSignupSignal()) {
|
||||||
<div class="skeleton w-full h-10 max-w-md"></div>
|
Anmelden
|
||||||
<div class="skeleton w-full h-10 max-w-md"></div>
|
} @else if (isRegisterSignal()) {
|
||||||
<div class="skeleton w-full h-10 max-w-md"></div>
|
Registrieren
|
||||||
</div>
|
} @else {
|
||||||
} @else {
|
Erste Schritte
|
||||||
<h1 class="text-3xl font-semibold text-center">Login</h1>
|
}
|
||||||
<form
|
</h1>
|
||||||
[formGroup]="form"
|
|
||||||
(ngSubmit)="onSubmit()"
|
@if (isDisplayButtons()) {
|
||||||
class="flex gap-4 flex-col items-center py-6 w-full max-w-md">
|
<div class="action">
|
||||||
<div class="form-control w-full">
|
<button
|
||||||
<label
|
pButton
|
||||||
[ngClass]="{
|
type="button"
|
||||||
'w-full': true,
|
label="Anmelden"
|
||||||
'border-error focus:border-error':
|
(click)="toggleAction('signup')"></button>
|
||||||
form.get('email')?.invalid &&
|
<button
|
||||||
(form.get('email')?.dirty || form.get('email')?.touched)
|
pButton
|
||||||
}"
|
type="button"
|
||||||
class="input input-bordered flex items-center gap-2">
|
label="Registrieren"
|
||||||
<svg
|
(click)="toggleAction('register')"></button>
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
</div>
|
||||||
viewBox="0 0 16 16"
|
}
|
||||||
fill="currentColor"
|
@if (isSignupSignal() || isRegisterSignal()) {
|
||||||
class="h-4 w-4 opacity-70">
|
<div class="register-wrapper">
|
||||||
<path
|
@if (form) {
|
||||||
d="M2.5 3A1.5 1.5 0 0 0 1 4.5v.793c.026.009.051.02.076.032L7.674 8.51c.206.1.446.1.652 0l6.598-3.185A.755.755 0 0 1 15 5.293V4.5A1.5 1.5 0 0 0 13.5 3h-11Z" />
|
<form [formGroup]="form" (ngSubmit)="onSubmit()">
|
||||||
<path
|
<div class="e-mail">
|
||||||
d="M15 6.954 8.978 9.86a2.25 2.25 0 0 1-1.956 0L1 6.954V11.5A1.5 1.5 0 0 0 2.5 13h11a1.5 1.5 0 0 0 1.5-1.5V6.954Z" />
|
<div class="label">
|
||||||
</svg>
|
<label for="email">E-Mail</label>
|
||||||
<input
|
|
||||||
formControlName="email"
|
|
||||||
type="text"
|
|
||||||
class="grow"
|
|
||||||
placeholder="name@example.com" />
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-control w-full">
|
|
||||||
<label
|
|
||||||
[ngClass]="{
|
|
||||||
'w-full': true,
|
|
||||||
'border-error focus:border-error':
|
|
||||||
form.get('password')?.invalid &&
|
|
||||||
(form.get('password')?.dirty ||
|
|
||||||
form.get('password')?.touched)
|
|
||||||
}"
|
|
||||||
class="input input-bordered flex items-center gap-2">
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 16 16"
|
|
||||||
fill="currentColor"
|
|
||||||
class="h-4 w-4 opacity-70">
|
|
||||||
<path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M14 6a4 4 0 0 1-4.899 3.899l-1.955 1.955a.5.5 0 0 1-.353.146H5v1.5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1-.5-.5v-2.293a.5.5 0 0 1 .146-.353l3.955-3.955A4 4 0 1 1 14 6Zm-4-2a.75.75 0 0 0 0 1.5.5.5 0 0 1 .5.5.75.75 0 0 0 1.5 0 2 2 0 0 0-2-2Z"
|
|
||||||
clip-rule="evenodd" />
|
|
||||||
</svg>
|
|
||||||
<input
|
|
||||||
formControlName="password"
|
|
||||||
type="password"
|
|
||||||
class="grow"
|
|
||||||
value="" />
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-control w-full">
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<label class="label cursor-pointer">
|
|
||||||
<input
|
|
||||||
[formControl]="rememberMe"
|
|
||||||
type="checkbox"
|
|
||||||
checked="checked"
|
|
||||||
class="checkbox checkbox-md checkbox-primary" />
|
|
||||||
<span class="label-text ml-1.5">Remember me</span>
|
|
||||||
</label>
|
|
||||||
<a class="text-primary label-text cursor-pointer">
|
|
||||||
Forgot password?
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
|
<input
|
||||||
|
pInputText
|
||||||
|
id="email"
|
||||||
|
formControlName="email"
|
||||||
|
aria-describedby="e-mail" />
|
||||||
</div>
|
</div>
|
||||||
<button class="btn w-full btn-primary font-semibold">
|
<div class="password">
|
||||||
@if (isLoading()) {
|
<div class="label">
|
||||||
<span class="loading loading-spinner"></span>
|
<label for="password">Password</label>
|
||||||
}
|
</div>
|
||||||
Sign In
|
<p-password
|
||||||
</button>
|
class="custom-p-password"
|
||||||
<div class="flex gap-1">
|
id="password"
|
||||||
<span class="text-xs">Not registered yet?</span>
|
formControlName="password"
|
||||||
|
aria-describedby="password"
|
||||||
|
[toggleMask]="true"></p-password>
|
||||||
|
</div>
|
||||||
|
@if (isRegisterSignal()) {
|
||||||
|
<div class="terms">
|
||||||
|
<p-checkbox
|
||||||
|
formControlName="terms"
|
||||||
|
label="Ich habe die AGB gelesen und stimme zu."
|
||||||
|
name="terms"
|
||||||
|
[binary]="true"></p-checkbox>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<div class="signup">
|
||||||
|
<button
|
||||||
|
pButton
|
||||||
|
type="submit"
|
||||||
|
[label]="
|
||||||
|
isSignupSignal()
|
||||||
|
? 'Anmelden'
|
||||||
|
: '✨ Jetzt KOSTENFREI loslegen ✨'
|
||||||
|
"></button>
|
||||||
|
</div>
|
||||||
|
<div class="change-mask">
|
||||||
<a
|
<a
|
||||||
(click)="toggleAction('signup')"
|
(click)="switchMask()"
|
||||||
(keypress)="toggleAction('signup')"
|
(keyup.enter)="switchMask()"
|
||||||
tabindex="0"
|
tabindex="0">
|
||||||
class="text-primary cursor-pointer text-xs">
|
@if (isSignupSignal()) {
|
||||||
Create An Account
|
Kein Account? Erstellen Sie jetzt KOSTENFREI einen!
|
||||||
|
} @else {
|
||||||
|
Schon einen Account? Hier einloggen
|
||||||
|
}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<div class="flex flex-col items-center justify-center py-12">
|
|
||||||
<footer>
|
|
||||||
<p class="text-xs">Made with ♥️ in Germany</p>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
}
|
||||||
} @else {
|
|
||||||
<div class="flex h-screen w-screen bg-primary">
|
|
||||||
<div class="hidden md:flex md:flex-col md:w-1/1"></div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
<div class="modal modal-open" *ngIf="isDialogOpen()">
|
|
||||||
<div
|
|
||||||
[ngStyle]="dialogBackgroundStyle"
|
|
||||||
class="modal-box w-11/12 h-2/6 max-w-5xl flex">
|
|
||||||
<div class="w-full flex flex-col justify-center items-center">
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
stroke-width="1"
|
|
||||||
stroke="currentColor"
|
|
||||||
class="size-28 animate-jump animate-once animate-duration-[2000ms] animate-delay-500 animate-ease-in-out animate-normal">
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
d="M21.75 9v.906a2.25 2.25 0 0 1-1.183 1.981l-6.478 3.488M2.25 9v.906a2.25 2.25 0 0 0 1.183 1.981l6.478 3.488m8.839 2.51-4.66-2.51m0 0-1.023-.55a2.25 2.25 0 0 0-2.134 0l-1.022.55m0 0-4.661 2.51m16.5 1.615a2.25 2.25 0 0 1-2.25 2.25h-15a2.25 2.25 0 0 1-2.25-2.25V8.844a2.25 2.25 0 0 1 1.183-1.981l7.5-4.039a2.25 2.25 0 0 1 2.134 0l7.5 4.039a2.25 2.25 0 0 1 1.183 1.98V19.5Z" />
|
|
||||||
</svg>
|
|
||||||
|
|
||||||
<h1 class="font-bold text-3xl pt-5">Check your inbox, please!</h1>
|
|
||||||
<div class="flex flex-col items-center text-center">
|
|
||||||
<p class="pt-3">
|
|
||||||
Hey, to start using [APP-NAME], we need to verify your email.
|
|
||||||
</p>
|
|
||||||
<p class="pt-1">
|
|
||||||
We´ve already sent out the verification link. Please check it and
|
|
||||||
<br />
|
|
||||||
confirm it´s really you.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
#background {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.img-zone {
|
||||||
|
flex: 65;
|
||||||
|
background-color: lightsalmon;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.img-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.success {
|
||||||
|
margin-left: 4em;
|
||||||
|
h1 {
|
||||||
|
font-size: 4em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.headline {
|
||||||
|
h1 {
|
||||||
|
font-size: 4em;
|
||||||
|
margin-left: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-zone {
|
||||||
|
flex: 35;
|
||||||
|
background-color: lightcyan;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.action {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 1em;
|
||||||
|
|
||||||
|
button {
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.register-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
padding: 0 0 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.e-mail,
|
||||||
|
.password,
|
||||||
|
.terms {
|
||||||
|
.label {
|
||||||
|
font-size: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
min-width: 500px;
|
||||||
|
}
|
||||||
|
::ng-deep p-password.custom-p-password div input {
|
||||||
|
min-width: 500px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.terms {
|
||||||
|
padding-top: 1.33em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.password {
|
||||||
|
padding-top: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.signup {
|
||||||
|
padding-top: 3em;
|
||||||
|
|
||||||
|
button {
|
||||||
|
min-width: 500px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.change-mask {
|
||||||
|
padding-top: 1.33em;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
a {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,7 +9,6 @@ import {
|
||||||
effect,
|
effect,
|
||||||
InputSignal,
|
InputSignal,
|
||||||
input,
|
input,
|
||||||
ElementRef,
|
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import {
|
import {
|
||||||
FormBuilder,
|
FormBuilder,
|
||||||
|
@ -25,7 +24,6 @@ import { ButtonModule } from 'primeng/button';
|
||||||
import { CheckboxModule } from 'primeng/checkbox';
|
import { CheckboxModule } from 'primeng/checkbox';
|
||||||
import { InputTextModule } from 'primeng/inputtext';
|
import { InputTextModule } from 'primeng/inputtext';
|
||||||
import { PasswordModule } from 'primeng/password';
|
import { PasswordModule } from 'primeng/password';
|
||||||
import { delay, finalize, tap } from 'rxjs';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Configuration,
|
Configuration,
|
||||||
|
@ -34,18 +32,13 @@ import {
|
||||||
UserCredentialsDtoApiModel,
|
UserCredentialsDtoApiModel,
|
||||||
} from '../../api';
|
} from '../../api';
|
||||||
import { ApiConfiguration } from '../../config/api-configuration';
|
import { ApiConfiguration } from '../../config/api-configuration';
|
||||||
import {
|
import { AuthService, SessionStorageService } from '../../shared/service';
|
||||||
AuthService,
|
|
||||||
BackgroundPatternService,
|
|
||||||
ThemeService,
|
|
||||||
} from '../../shared/service';
|
|
||||||
import { LocalStorageService } from '../../shared/service/local-storage.service';
|
|
||||||
import {
|
import {
|
||||||
customEmailValidator,
|
customEmailValidator,
|
||||||
customPasswordValidator,
|
customPasswordValidator,
|
||||||
} from '../../shared/validator';
|
} from '../../shared/validator';
|
||||||
|
|
||||||
type AuthAction = 'signin' | 'signup';
|
type AuthAction = 'register' | 'signup';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-register-root',
|
selector: 'app-register-root',
|
||||||
|
@ -72,68 +65,47 @@ type AuthAction = 'signin' | 'signup';
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class RegisterRootComponent implements OnInit {
|
export class RegisterRootComponent implements OnInit {
|
||||||
public dialogBackgroundStyle: { 'background-image': string } | null = null;
|
|
||||||
public leftBackgroundStyle: { 'background-image': string } | null = null;
|
|
||||||
public rightBackgroundStyle: { 'background-image': string } | null = null;
|
|
||||||
public verified: InputSignal<boolean> = input<boolean>(false);
|
public verified: InputSignal<boolean> = input<boolean>(false);
|
||||||
public login: InputSignal<boolean> = input<boolean>(false);
|
public login: InputSignal<boolean> = input<boolean>(false);
|
||||||
public email: InputSignal<string> = input<string>('');
|
public email: InputSignal<string> = input<string>('');
|
||||||
public form!: FormGroup;
|
public form: FormGroup | undefined;
|
||||||
public rememberMe: FormControl = new FormControl(false);
|
public isRegisterSignal: WritableSignal<boolean> = signal(false);
|
||||||
public isSigninSignal: WritableSignal<boolean> = signal(false);
|
public isSignupSignal: WritableSignal<boolean> = signal(false);
|
||||||
public isSignupSignal: WritableSignal<boolean> = signal(true);
|
public isDisplayButtons: WritableSignal<boolean> = signal(true);
|
||||||
public isSignUpSuccess: WritableSignal<boolean> = signal(false);
|
public emailInvalid: WritableSignal<string | null> = signal(null);
|
||||||
|
public passwordInvalid: WritableSignal<string | null> = signal(null);
|
||||||
|
public termsInvalid: WritableSignal<string | null> = signal(null);
|
||||||
public userSignupSuccess: WritableSignal<boolean> = signal(false);
|
public userSignupSuccess: WritableSignal<boolean> = signal(false);
|
||||||
public isDialogOpen: WritableSignal<boolean> = signal(false);
|
|
||||||
public isLoading: WritableSignal<boolean> = signal(false);
|
|
||||||
public displaySkeleton: WritableSignal<boolean> = signal(true);
|
|
||||||
private removeQueryParams: WritableSignal<boolean> = signal(false);
|
private removeQueryParams: WritableSignal<boolean> = signal(false);
|
||||||
|
|
||||||
public get isDarkMode(): boolean {
|
|
||||||
return this.themeService.getTheme() === 'dark';
|
|
||||||
}
|
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
private readonly formBuilder: FormBuilder,
|
private readonly formBuilder: FormBuilder,
|
||||||
private readonly authService: AuthService,
|
private readonly authService: AuthService,
|
||||||
private readonly router: Router,
|
private readonly router: Router,
|
||||||
private readonly themeService: ThemeService,
|
private readonly sessionStorageService: SessionStorageService
|
||||||
private readonly el: ElementRef,
|
|
||||||
private readonly backgroundPatternService: BackgroundPatternService,
|
|
||||||
private readonly localStorageService: LocalStorageService
|
|
||||||
) {
|
) {
|
||||||
effect(() => {
|
effect(() => {
|
||||||
|
if (this.form) {
|
||||||
|
if (this.isRegisterSignal()) {
|
||||||
|
this.form.addControl(
|
||||||
|
'terms',
|
||||||
|
new FormControl(false, Validators.requiredTrue)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.form.removeControl('terms');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (this.removeQueryParams()) {
|
if (this.removeQueryParams()) {
|
||||||
this.clearRouteParams();
|
this.clearRouteParams();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const rememberMe = this.localStorageService.getItem<boolean>('remember-me');
|
|
||||||
|
|
||||||
if (rememberMe) {
|
|
||||||
this.authService
|
|
||||||
.status()
|
|
||||||
.pipe(delay(1500))
|
|
||||||
.subscribe({
|
|
||||||
next: (response: SuccessDtoApiModel) => {
|
|
||||||
if (response.success) {
|
|
||||||
this.router.navigate(['/dashboard']);
|
|
||||||
} else {
|
|
||||||
this.displaySkeleton.set(false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
error: () => {
|
|
||||||
this.displaySkeleton.set(false);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.displaySkeleton.set(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ngOnInit(): void {
|
public ngOnInit(): void {
|
||||||
this.setBackground();
|
|
||||||
this.initializeForm();
|
this.initializeForm();
|
||||||
this.setupValueChanges();
|
this.setupValueChanges();
|
||||||
|
this.preselectForm();
|
||||||
|
|
||||||
if ((this.email() && this.verified()) || this.login()) {
|
if ((this.email() && this.verified()) || this.login()) {
|
||||||
this.handleRedirect();
|
this.handleRedirect();
|
||||||
|
@ -141,116 +113,52 @@ export class RegisterRootComponent implements OnInit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public setBackground(): void {
|
public preselectForm(): void {
|
||||||
const theme = this.themeService.getTheme();
|
if (!this.email() || !this.verified()) {
|
||||||
let opacity: number;
|
const email = this.sessionStorageService.getItem('email');
|
||||||
|
|
||||||
if (theme === 'dark') {
|
this.form?.get('email')?.setValue(email);
|
||||||
opacity = 0.05;
|
|
||||||
} else {
|
|
||||||
opacity = 0.1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const colorPrimary = getComputedStyle(
|
|
||||||
this.el.nativeElement
|
|
||||||
).getPropertyValue('--p');
|
|
||||||
|
|
||||||
const colorPrimaryC = getComputedStyle(
|
|
||||||
this.el.nativeElement
|
|
||||||
).getPropertyValue('--pc');
|
|
||||||
|
|
||||||
const svgUrlforDialog = this.backgroundPatternService.getWigglePattern(
|
|
||||||
colorPrimary,
|
|
||||||
opacity
|
|
||||||
);
|
|
||||||
const svgUrlForLeft = this.backgroundPatternService.getBankNotePattern(
|
|
||||||
colorPrimaryC,
|
|
||||||
opacity
|
|
||||||
);
|
|
||||||
const svgUrlForRight = this.backgroundPatternService.getHideoutPattern(
|
|
||||||
colorPrimary,
|
|
||||||
opacity
|
|
||||||
);
|
|
||||||
|
|
||||||
this.dialogBackgroundStyle = {
|
|
||||||
'background-image': `url("${svgUrlforDialog}")`,
|
|
||||||
};
|
|
||||||
this.leftBackgroundStyle = {
|
|
||||||
'background-image': `url("${svgUrlForLeft}")`,
|
|
||||||
};
|
|
||||||
this.rightBackgroundStyle = {
|
|
||||||
'background-image': `url("${svgUrlForRight}")`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public openModal(): void {
|
|
||||||
this.isDialogOpen.set(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public closeModal(): void {
|
|
||||||
this.isDialogOpen.set(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public toggleTheme(): void {
|
|
||||||
this.themeService.toggleTheme();
|
|
||||||
this.setBackground();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public toggleAction(action: AuthAction): void {
|
public toggleAction(action: AuthAction): void {
|
||||||
this.resetFormValidation();
|
if (action === 'register') {
|
||||||
|
this.isRegisterSignal.set(true);
|
||||||
if (action === 'signin') {
|
|
||||||
this.handlePreselect();
|
|
||||||
this.isSigninSignal.set(true);
|
|
||||||
this.isSignupSignal.set(false);
|
this.isSignupSignal.set(false);
|
||||||
} else {
|
} else {
|
||||||
this.isSigninSignal.set(false);
|
this.isRegisterSignal.set(false);
|
||||||
this.isSignupSignal.set(true);
|
this.isSignupSignal.set(true);
|
||||||
}
|
}
|
||||||
|
this.isDisplayButtons.set(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public onSubmit(): void {
|
public onSubmit(): void {
|
||||||
this.markControlsAsTouchedAndDirty(['email', 'password']);
|
this.markControlsAsTouchedAndDirty(['email', 'password', 'terms']);
|
||||||
|
|
||||||
if (this.form?.valid) {
|
if (this.form?.valid) {
|
||||||
if (this.isSigninSignal()) {
|
if (this.isRegisterSignal()) {
|
||||||
this.signin(this.form.value);
|
|
||||||
} else {
|
|
||||||
this.signup(this.form.value);
|
this.signup(this.form.value);
|
||||||
|
} else {
|
||||||
|
this.signin(this.form.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private handlePreselect(): void {
|
public switchMask(): void {
|
||||||
const rememberMe = this.localStorageService.getItem<boolean>('remember-me');
|
this.resetFormValidation();
|
||||||
const email = this.localStorageService.getItem<string>('email');
|
|
||||||
|
|
||||||
if (rememberMe) {
|
if (this.isSignupSignal()) {
|
||||||
this.isSigninSignal.set(true);
|
|
||||||
this.isSignupSignal.set(false);
|
this.isSignupSignal.set(false);
|
||||||
|
this.isRegisterSignal.set(true);
|
||||||
|
} else if (this.isRegisterSignal()) {
|
||||||
|
this.isSignupSignal.set(true);
|
||||||
|
this.isRegisterSignal.set(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (email) {
|
|
||||||
this.form?.get('email')?.setValue(email);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.rememberMe.setValue(rememberMe);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeForm(): void {
|
private initializeForm(): void {
|
||||||
const rememberMeValue =
|
|
||||||
this.localStorageService.getItem<boolean>('remember-me');
|
|
||||||
const email = this.localStorageService.getItem<string>('email');
|
|
||||||
|
|
||||||
if (rememberMeValue) {
|
|
||||||
this.isSigninSignal.set(true);
|
|
||||||
this.isSignupSignal.set(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
const emailValue = rememberMeValue && email ? email : '';
|
|
||||||
|
|
||||||
this.form = this.formBuilder.group({
|
this.form = this.formBuilder.group({
|
||||||
email: new FormControl(emailValue, {
|
email: new FormControl('', {
|
||||||
validators: [Validators.required, customEmailValidator()],
|
validators: [Validators.required, customEmailValidator()],
|
||||||
updateOn: 'change',
|
updateOn: 'change',
|
||||||
}),
|
}),
|
||||||
|
@ -258,15 +166,18 @@ export class RegisterRootComponent implements OnInit {
|
||||||
validators: [Validators.required, customPasswordValidator()],
|
validators: [Validators.required, customPasswordValidator()],
|
||||||
updateOn: 'change',
|
updateOn: 'change',
|
||||||
}),
|
}),
|
||||||
|
terms: new FormControl(false, {
|
||||||
|
validators: [Validators.requiredTrue],
|
||||||
|
updateOn: 'change',
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
this.rememberMe.setValue(rememberMeValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleRedirect(): void {
|
private handleRedirect(): void {
|
||||||
if (this.verified()) {
|
if (this.verified()) {
|
||||||
this.isSigninSignal.set(true);
|
this.isDisplayButtons.set(false);
|
||||||
this.isSignupSignal.set(false);
|
this.isRegisterSignal.set(false);
|
||||||
|
this.isSignupSignal.set(true);
|
||||||
}
|
}
|
||||||
if (this.email()) {
|
if (this.email()) {
|
||||||
this.form?.get('email')?.setValue(decodeURIComponent(atob(this.email())));
|
this.form?.get('email')?.setValue(decodeURIComponent(atob(this.email())));
|
||||||
|
@ -274,7 +185,8 @@ export class RegisterRootComponent implements OnInit {
|
||||||
|
|
||||||
if (this.login()) {
|
if (this.login()) {
|
||||||
this.isSignupSignal.set(true);
|
this.isSignupSignal.set(true);
|
||||||
this.isSigninSignal.set(false);
|
this.isDisplayButtons.set(false);
|
||||||
|
this.isRegisterSignal.set(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,7 +250,7 @@ export class RegisterRootComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
private resetFormValidation(): void {
|
private resetFormValidation(): void {
|
||||||
['email', 'password'].forEach((controlName: string) => {
|
['email', 'password', 'terms'].forEach((controlName: string) => {
|
||||||
this.resetControlValidation(controlName);
|
this.resetControlValidation(controlName);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -355,20 +267,8 @@ export class RegisterRootComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
private signin(logiCredentials: UserCredentialsDtoApiModel): void {
|
private signin(logiCredentials: UserCredentialsDtoApiModel): void {
|
||||||
const rememberMe: boolean = this.rememberMe.value;
|
|
||||||
|
|
||||||
if (rememberMe) {
|
|
||||||
this.localStorageService.setItem<string>('email', logiCredentials.email);
|
|
||||||
this.localStorageService.setItem<boolean>('remember-me', rememberMe);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.authService
|
this.authService
|
||||||
.signin(logiCredentials)
|
.signin(logiCredentials)
|
||||||
.pipe(
|
|
||||||
tap(() => this.isLoading.set(true)),
|
|
||||||
delay(1000),
|
|
||||||
finalize(() => this.isLoading.set(false))
|
|
||||||
)
|
|
||||||
.subscribe((response: SigninResponseDtoApiModel) => {
|
.subscribe((response: SigninResponseDtoApiModel) => {
|
||||||
if (response) {
|
if (response) {
|
||||||
this.router.navigate(['/dashboard']);
|
this.router.navigate(['/dashboard']);
|
||||||
|
@ -377,17 +277,10 @@ export class RegisterRootComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
private signup(logiCredentials: UserCredentialsDtoApiModel): void {
|
private signup(logiCredentials: UserCredentialsDtoApiModel): void {
|
||||||
this.isLoading.set(true);
|
|
||||||
this.authService
|
this.authService
|
||||||
.signup(logiCredentials)
|
.signup(logiCredentials)
|
||||||
.pipe(
|
|
||||||
delay(1000),
|
|
||||||
tap(() => this.isLoading.set(true)),
|
|
||||||
finalize(() => this.isLoading.set(false))
|
|
||||||
)
|
|
||||||
.subscribe((response: SuccessDtoApiModel) => {
|
.subscribe((response: SuccessDtoApiModel) => {
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
this.openModal();
|
|
||||||
this.userSignupSuccess.set(true);
|
this.userSignupSuccess.set(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,137 +0,0 @@
|
||||||
import { Injectable } from '@angular/core';
|
|
||||||
|
|
||||||
import chroma from 'chroma-js';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root',
|
|
||||||
})
|
|
||||||
export class BackgroundPatternService {
|
|
||||||
public getWigglePattern(color: string, opacity: number): string {
|
|
||||||
const colorHex = this.convertOklchStringToHex(color);
|
|
||||||
const encodedHex = encodeURIComponent(colorHex);
|
|
||||||
const pattern = `
|
|
||||||
data:image/svg+xml,
|
|
||||||
%3Csvg width='52' height='26' viewBox='0 0 52 26' xmlns='http://www.w3.org/2000/svg'%3E
|
|
||||||
%3Cg fill='none' fill-rule='evenodd'%3E
|
|
||||||
%3Cg fill='${encodedHex}' fill-opacity='${opacity}'%3E
|
|
||||||
%3Cpath d='M10 10c0-2.21-1.79-4-4-4-3.314 0-6-2.686-6-6h2c0 2.21 1.79 4 4 4 3.314 0 6 2.686 6 6 0 2.21 1.79 4 4 4 3.314 0 6 2.686 6 6 0 2.21 1.79 4 4 4v2c-3.314 0-6-2.686-6-6 0-2.21-1.79-4-4-4-3.314 0-6-2.686-6-6zm25.464-1.95l8.486 8.486-1.414 1.414-8.486-8.486 1.414-1.414z' /%3E
|
|
||||||
%3C/g%3E
|
|
||||||
%3C/g%3E
|
|
||||||
%3C/svg%3E`;
|
|
||||||
|
|
||||||
return pattern.replace(/[\n\r]+|[\s]{2,}/g, ' ').trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
public getTexturePattern(color: string, opacity: number): string {
|
|
||||||
const colorHex = this.convertOklchStringToHex(color);
|
|
||||||
const encodedHex = encodeURIComponent(colorHex);
|
|
||||||
const pattern = `
|
|
||||||
data:image/svg+xml,
|
|
||||||
%3Csvg xmlns='http://www.w3.org/2000/svg' width='4' height='4' viewBox='0 0 4 4'%3E
|
|
||||||
%3Cpath fill='${encodedHex}' fill-opacity='${opacity}' d='M1 3h1v1H1V3zm2-2h1v1H3V1z'%3E
|
|
||||||
%3C/path%3E
|
|
||||||
%3C/svg%3E`;
|
|
||||||
|
|
||||||
return pattern.replace(/[\n\r]+|[\s]{2,}/g, ' ').trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
public getBubblesPattern(color: string, opacity: number): string {
|
|
||||||
const colorHex = this.convertOklchStringToHex(color);
|
|
||||||
const encodedHex = encodeURIComponent(colorHex);
|
|
||||||
const pattern = `
|
|
||||||
data:image/svg+xml,
|
|
||||||
%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E
|
|
||||||
%3Cpath d='M11 18c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm48 25c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm-43-7c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm63 31c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM34 90c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm56-76c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM12 86c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm28-65c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm23-11c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-6 60c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm29 22c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zM32 63c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm57-13c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-9-21c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM60 91c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM35 41c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM12 60c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2z' fill='${encodedHex}' fill-opacity='${opacity}' fill-rule='evenodd'/%3E
|
|
||||||
%3C/svg%3E`;
|
|
||||||
|
|
||||||
return pattern.replace(/[\n\r]+|[\s]{2,}/g, ' ').trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
public getBankNotePattern(color: string, opacity: number): string {
|
|
||||||
const colorHex = this.convertOklchStringToHex(color);
|
|
||||||
const encodedHex = encodeURIComponent(colorHex);
|
|
||||||
const pattern = `
|
|
||||||
data:image/svg+xml,
|
|
||||||
%3Csvg width='100' height='20' viewBox='0 0 100 20' xmlns='http://www.w3.org/2000/svg'%3E
|
|
||||||
%3Cpath d='M21.184 20c.357-.13.72-.264 1.088-.402l1.768-.661C33.64 15.347 39.647 14 50 14c10.271 0 15.362 1.222 24.629 4.928.955.383 1.869.74 2.75 1.072h6.225c-2.51-.73-5.139-1.691-8.233-2.928C65.888 13.278 60.562 12 50 12c-10.626 0-16.855 1.397-26.66 5.063l-1.767.662c-2.475.923-4.66 1.674-6.724 2.275h6.335zm0-20C13.258 2.892 8.077 4 0 4V2c5.744 0 9.951-.574 14.85-2h6.334zM77.38 0C85.239 2.966 90.502 4 100 4V2c-6.842 0-11.386-.542-16.396-2h-6.225zM0 14c8.44 0 13.718-1.21 22.272-4.402l1.768-.661C33.64 5.347 39.647 4 50 4c10.271 0 15.362 1.222 24.629 4.928C84.112 12.722 89.438 14 100 14v-2c-10.271 0-15.362-1.222-24.629-4.928C65.888 3.278 60.562 2 50 2 39.374 2 33.145 3.397 23.34 7.063l-1.767.662C13.223 10.84 8.163 12 0 12v2z' fill='${encodedHex}' fill-opacity='${opacity}' fill-rule='evenodd'/%3E
|
|
||||||
%3C/svg%3E`;
|
|
||||||
|
|
||||||
return pattern.replace(/[\n\r]+|[\s]{2,}/g, ' ').trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
public getHideoutPattern(color: string, opacity: number): string {
|
|
||||||
const colorHex = this.convertOklchStringToHex(color);
|
|
||||||
const encodedHex = encodeURIComponent(colorHex);
|
|
||||||
const pattern = `
|
|
||||||
data:image/svg+xml,
|
|
||||||
%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40' viewBox='0 0 40 40'%3E
|
|
||||||
%3Cg fill-rule='evenodd'%3E
|
|
||||||
%3Cg fill='${encodedHex}' fill-opacity='${opacity}'%3E
|
|
||||||
%3Cpath d='M0 38.59l2.83-2.83 1.41 1.41L1.41 40H0v-1.41zM0 1.4l2.83 2.83 1.41-1.41L1.41 0H0v1.41zM38.59 40l-2.83-2.83 1.41-1.41L40 38.59V40h-1.41zM40 1.41l-2.83 2.83-1.41-1.41L38.59 0H40v1.41zM20 18.6l2.83-2.83 1.41 1.41L21.41 20l2.83 2.83-1.41 1.41L20 21.41l-2.83 2.83-1.41-1.41L18.59 20l-2.83-2.83 1.41-1.41L20 18.59z'/%3E
|
|
||||||
%3C/g%3E
|
|
||||||
%3C/g%3E
|
|
||||||
%3C/svg%3E`;
|
|
||||||
|
|
||||||
return pattern.replace(/[\n\r]+|[\s]{2,}/g, ' ').trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
public getFourPointsStarsPattern(color: string, opacity: number): string {
|
|
||||||
const colorHex = this.convertOklchStringToHex(color);
|
|
||||||
const encodedHex = encodeURIComponent(colorHex);
|
|
||||||
const pattern = `
|
|
||||||
data:image/svg+xml,
|
|
||||||
%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E
|
|
||||||
%3Cg fill='${encodedHex}' fill-opacity='${opacity}'%3E
|
|
||||||
%3Cpolygon fill-rule='evenodd' points='8 4 12 6 8 8 6 12 4 8 0 6 4 4 6 0 8 4'/%3E
|
|
||||||
%3C/g%3E
|
|
||||||
%3C/svg%3E`;
|
|
||||||
|
|
||||||
return pattern.replace(/[\n\r]+|[\s]{2,}/g, ' ').trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
public getPlusPattern(color: string, opacity: number): string {
|
|
||||||
const colorHex = this.convertOklchStringToHex(color);
|
|
||||||
const encodedHex = encodeURIComponent(colorHex);
|
|
||||||
const pattern = `
|
|
||||||
data:image/svg+xml,
|
|
||||||
%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E
|
|
||||||
%3Cg fill='none' fill-rule='evenodd'%3E
|
|
||||||
%3Cg fill='${encodedHex}' fill-opacity='${opacity}'%3E
|
|
||||||
%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E
|
|
||||||
%3C/g%3E
|
|
||||||
%3C/g%3E
|
|
||||||
%3C/svg%3E`;
|
|
||||||
|
|
||||||
return pattern.replace(/[\n\r]+|[\s]{2,}/g, ' ').trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
public getPolkaDotsPattern(color: string, opacity: number = 0.4): string {
|
|
||||||
const colorHex = this.convertOklchStringToHex(color);
|
|
||||||
const encodedHex = encodeURIComponent(colorHex);
|
|
||||||
const pattern = `
|
|
||||||
data:image/svg+xml,
|
|
||||||
%3Csvg width='20' height='20' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg'%3E
|
|
||||||
%3Cg fill='${encodedHex}' fill-opacity='${opacity}' fill-rule='evenodd'%3E
|
|
||||||
%3Ccircle cx='3' cy='3' r='3'/%3E
|
|
||||||
%3Ccircle cx='13' cy='13' r='3'/%3E
|
|
||||||
%3C/g%3E
|
|
||||||
%3C/svg%3E`;
|
|
||||||
|
|
||||||
return pattern.replace(/[\n\r]+|[\s]{2,}/g, ' ').trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
private convertOklchStringToHex(oklchString: string): string {
|
|
||||||
const parts = oklchString.split(' ');
|
|
||||||
const l = parseFloat(parts[0]);
|
|
||||||
const c = parseFloat(parts[1]);
|
|
||||||
const h = parseFloat(parts[2]);
|
|
||||||
|
|
||||||
return this.convertOklchToHex(l / 100, c, h);
|
|
||||||
}
|
|
||||||
|
|
||||||
private convertOklchToHex(l: number, c: number, h: number): string {
|
|
||||||
const rgb = chroma.oklch(l, c, h).rgb();
|
|
||||||
|
|
||||||
return chroma(rgb).hex();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,3 @@
|
||||||
export * from './auth.service';
|
export * from './auth.service';
|
||||||
export * from './local-storage.service';
|
export * from './local-storage.service';
|
||||||
export * from './session-storage.service';
|
export * from './session-storage.service';
|
||||||
export * from './theme.service';
|
|
||||||
export * from './background-pattern.service';
|
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
import { Injectable } from '@angular/core';
|
|
||||||
|
|
||||||
import { LocalStorageService } from './local-storage.service';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root',
|
|
||||||
})
|
|
||||||
export class ThemeService {
|
|
||||||
private currentTheme: string = '';
|
|
||||||
|
|
||||||
public constructor(private storageService: LocalStorageService) {
|
|
||||||
this.loadInitialTheme();
|
|
||||||
}
|
|
||||||
|
|
||||||
public getTheme(): string {
|
|
||||||
return this.currentTheme;
|
|
||||||
}
|
|
||||||
|
|
||||||
public setTheme(theme: string): void {
|
|
||||||
this.currentTheme = theme;
|
|
||||||
this.storageService.setItem('theme', theme);
|
|
||||||
this.applyTheme(theme);
|
|
||||||
}
|
|
||||||
|
|
||||||
public toggleTheme(): void {
|
|
||||||
this.currentTheme = this.currentTheme === 'light' ? 'dark' : 'light';
|
|
||||||
this.setTheme(this.currentTheme);
|
|
||||||
}
|
|
||||||
|
|
||||||
private applyTheme(theme: string): void {
|
|
||||||
document.body.setAttribute('data-theme', theme);
|
|
||||||
}
|
|
||||||
|
|
||||||
private loadInitialTheme(): void {
|
|
||||||
const savedTheme = this.storageService.getItem<string>('theme');
|
|
||||||
|
|
||||||
this.currentTheme = savedTheme ? savedTheme : 'light';
|
|
||||||
this.applyTheme(this.currentTheme);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +1,12 @@
|
||||||
// Import PrimeNG styles
|
// Import PrimeNG styles
|
||||||
// @import 'primeng/resources/themes/lara-light-blue/theme.css';
|
@import 'primeng/resources/themes/lara-light-blue/theme.css';
|
||||||
// @import 'primeng/resources/primeng.css';
|
@import 'primeng/resources/primeng.css';
|
||||||
|
|
||||||
// // PrimeNG icons
|
// PrimeNG icons
|
||||||
// @import 'primeicons/primeicons.css';
|
@import 'primeicons/primeicons.css';
|
||||||
|
|
||||||
@tailwind base;
|
html,
|
||||||
@tailwind components;
|
body {
|
||||||
@tailwind utilities;
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
/** @type {import('tailwindcss').Config} */
|
|
||||||
module.exports = {
|
|
||||||
content: [
|
|
||||||
"./src/**/*.{html,ts}",
|
|
||||||
],
|
|
||||||
theme: {
|
|
||||||
extend: {},
|
|
||||||
},
|
|
||||||
plugins: [require('daisyui'), require('tailwindcss-animated')],
|
|
||||||
daisyui: {
|
|
||||||
themes: ["light", "dark"],
|
|
||||||
darkMode: ['class', '[data-theme="dark"]']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue