Improve Aesthetics of Login and Admin Setup Views

This commit is contained in:
aditya.chandel
2025-07-04 19:08:28 -06:00
committed by Aditya Chandel
parent 8edf589f3d
commit 897a3c2fb6
9 changed files with 343 additions and 339 deletions

View File

@@ -8,6 +8,7 @@ import {ConfirmDialog} from 'primeng/confirmdialog';
import {Toast} from 'primeng/toast';
import {RouterOutlet} from '@angular/router';
import {AuthInitializationService} from './auth-initialization-service';
import {AppConfigService} from './core/service/app-config.service';
@Component({
selector: 'app-root',
@@ -23,6 +24,7 @@ export class AppComponent implements OnInit {
private bookService = inject(BookService);
private rxStompService = inject(RxStompService);
private eventService = inject(EventService);
private appConfigService = inject(AppConfigService);
ngOnInit(): void {

View File

@@ -1,41 +1,79 @@
<div class="login-container" >
<div class="login-wrapper">
<h1 class="app-title">BookLore</h1>
<p-card class="w-96">
<ng-template pTemplate="title">
<div class="text-center pb-2">Login</div>
</ng-template>
<ng-template pTemplate="content">
<div class="flex items-center justify-center min-h-screen min-w-[100vw] overflow-hidden"
style="background: linear-gradient(60deg, var(--primary-color) 0%, #1e3a8a 100%);">
<div class="flex flex-col items-center justify-center -mt-48">
<div style="border-radius: 56px; padding: 0.3rem; background: linear-gradient(180deg, var(--primary-color) 10%, rgba(33, 150, 243, 0) 30%)">
<div class="w-full bg-surface-0 dark:bg-surface-900 py-16 px-8 sm:px-16" style="border-radius: 53px">
<div class="text-center mb-8">
<svg class="mb-8 w-16 h-16 mx-auto" viewBox="0 0 126 126" fill="var(--primary-color)" xmlns="http://www.w3.org/2000/svg">
<path
d="M59 4.79297C71.5051 11.5557 80 24.7854 80 40C80 40.5959 79.987 41.1888 79.9609 41.7783C79.8609 44.0406 81.7355 46 84 46C106.091 46 124 63.9086 124 86C124 108.091 106.091 126 84 126H10C4.47715 126 0 121.523 0 116V39.0068L0.0126953 38.9941C0.357624 25.0252 7.86506 12.8347 19 5.95215V63.832C19 64.8345 20.0676 65.4391 20.9121 64.9902L21.0771 64.8867L38.2227 52.3428C38.6819 52.0068 39.3064 52.0068 39.7656 52.3428L56.9229 64.8945L57.0879 64.998C57.9324 65.447 59 64.8423 59 63.8398V4.79297Z"/>
<path
d="M40 0C43.8745 0 47.6199 0.552381 51.1631 1.58008V50.9697L44.3926 46.0176L44.0879 45.8037C40.9061 43.6679 36.7098 43.7393 33.5957 46.0176L26.8369 50.9619V2.21875C30.9593 0.782634 35.3881 0 40 0Z"
fill="white"/>
</svg>
<div class="text-3xl font-medium mb-4">Welcome to Booklore</div>
<span class="text-muted-color font-medium">Sign in to continue</span>
</div>
<form class="flex flex-col gap-4" #loginForm="ngForm" (ngSubmit)="login()">
<div class="flex flex-col gap-2">
<label for="username">Username</label>
<input fluid pInputText id="username" [(ngModel)]="username" name="username" required/>
<label for="username" class="text-xl font-medium">Username</label>
<input
pInputText
id="username"
name="username"
required
[(ngModel)]="username"
placeholder="Enter your username"
class="w-full md:w-[30rem]"
/>
</div>
<div class="flex flex-col gap-2">
<label for="password">Password</label>
<p-password fluid id="password" [(ngModel)]="password" name="password" [feedback]="false" required></p-password>
<label for="password" class="text-xl font-medium">Password</label>
<p-password
id="password"
name="password"
required
[(ngModel)]="password"
[feedback]="false"
placeholder="Enter your password"
[toggleMask]="true"
styleClass="mb-4"
[fluid]="true"
></p-password>
</div>
<div class="flex flex-col gap-3 mt-4">
<p-button
type="submit"
label="Login"
icon="pi pi-sign-in"
[disabled]="!loginForm.valid || !username || !password"
styleClass="w-full"
></p-button>
@if (errorMessage) {
<p-message severity="error" text="{{ errorMessage }}"></p-message>
}
@if (oidcEnabled) {
<div class="flex items-center gap-2 my-2">
<hr class="flex-grow" style="border: none; border-top: 1px solid var(--border-color);"/>
<span class="text-gray-300">or</span>
<hr class="flex-grow" style="border: none; border-top: 1px solid var(--border-color);"/>
</div>
<p-button
fluid
severity="primary"
type="submit"
label="Login"
icon="pi pi-sign-in"
[disabled]="!loginForm.valid || !username || !password">
</p-button>
@if (errorMessage) {
<p-message severity="error" text="{{ errorMessage }}"></p-message>
}
@if (oidcEnabled) {
<div>
<p-divider></p-divider>
<p-button fluid severity="info" type="button" label="Login with {{oidcName}}" icon="pi pi-id-card" (click)="loginWithOidc()"></p-button>
</div>
}
</div>
severity="info"
label="Login with {{ oidcName }}"
icon="pi pi-id-card"
(click)="loginWithOidc()"
styleClass="w-full bg-gray-800 text-white hover:bg-gray-700"
/>
}
</form>
</ng-template>
</p-card>
</div>
</div>
</div>
</div>

View File

@@ -1,25 +0,0 @@
.login-container {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: linear-gradient(to bottom right, #1e3a8a, #06b6d4, #3b82f6);
position: relative;
}
.login-wrapper {
display: flex;
flex-direction: column;
align-items: center;
gap: 1.5rem;
position: absolute;
top: 25%;
transform: translateY(-25%);
}
.app-title {
font-size: 3rem;
font-weight: 800;
color: white;
text-shadow: 0px 4px 6px rgba(0, 0, 0, 0.3);
}

View File

@@ -2,15 +2,11 @@ import {Component, inject, OnInit} from '@angular/core';
import {AuthService} from '../../service/auth.service';
import {Router} from '@angular/router';
import {FormsModule} from '@angular/forms';
import {Card} from 'primeng/card';
import {Password} from 'primeng/password';
import {Button} from 'primeng/button';
import {Message} from 'primeng/message';
import {PrimeTemplate} from 'primeng/api';
import {InputText} from 'primeng/inputtext';
import {OAuthService} from 'angular-oauth2-oidc';
import {Divider} from 'primeng/divider';
import {AppSettingsService} from '../../service/app-settings.service';
import {AppSettings} from '../../model/app-settings.model';
import {Observable} from 'rxjs';
@@ -20,14 +16,11 @@ import {filter, take} from 'rxjs/operators';
selector: 'app-login',
imports: [
FormsModule,
Card,
Password,
Button,
Message,
PrimeTemplate,
InputText,
Divider
],
InputText
],
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss']
})

View File

@@ -1,7 +1,16 @@
import {DOCUMENT, isPlatformBrowser} from '@angular/common';
import {effect, inject, Injectable, PLATFORM_ID, signal} from '@angular/core';
import {$t, updatePreset, updateSurfacePalette} from '@primeng/themes';
import Aura from '@primeng/themes/aura';
import {AppState} from '../model/app-state.model';
type ColorPalette = Record<string, string>;
interface Palette {
name: string;
palette: ColorPalette;
}
@Injectable({
providedIn: 'root',
})
@@ -12,21 +21,129 @@ export class AppConfigService {
platformId = inject(PLATFORM_ID);
private initialized = false;
readonly surfaces: Palette[] = [
{
name: 'neutral',
palette: {
0: '#ffffff',
50: '#fafafa',
100: '#f5f5f5',
200: '#e5e5e5',
300: '#d4d4d4',
400: '#a3a3a3',
500: '#737373',
600: '#525252',
700: '#404040',
800: '#262626',
900: '#171717',
950: '#0a0a0a'
}
},
{
name: 'zinc',
palette: {
0: '#ffffff',
50: '#fafafa',
100: '#f4f4f5',
200: '#e4e4e7',
300: '#d4d4d8',
400: '#a1a1aa',
500: '#71717a',
600: '#52525b',
700: '#3f3f46',
800: '#27272a',
900: '#18181b',
950: '#09090b'
}
},
{
name: 'stone',
palette: {
0: '#ffffff',
50: '#fafaf9',
100: '#f5f5f4',
200: '#e7e5e4',
300: '#d6d3d1',
400: '#a8a29e',
500: '#78716c',
600: '#57534e',
700: '#44403c',
800: '#292524',
900: '#1c1917',
950: '#0c0a09'
}
},
{
name: 'soho',
palette: {
0: '#ffffff',
50: '#ececec',
100: '#dedfdf',
200: '#c4c4c6',
300: '#adaeb0',
400: '#97979b',
500: '#7f8084',
600: '#6a6b70',
700: '#55565b',
800: '#3f4046',
900: '#2c2c34',
950: '#16161d'
}
},
{
name: 'viva',
palette: {
0: '#ffffff',
50: '#f3f3f3',
100: '#e7e7e8',
200: '#cfd0d0',
300: '#b7b8b9',
400: '#9fa1a1',
500: '#87898a',
600: '#6e7173',
700: '#565a5b',
800: '#3e4244',
900: '#262b2c',
950: '#0e1315'
}
},
{
name: 'ocean',
palette: {
0: '#ffffff',
50: '#fbfcfc',
100: '#F7F9F8',
200: '#EFF3F2',
300: '#DADEDD',
400: '#B1B7B6',
500: '#828787',
600: '#5F7274',
700: '#415B61',
800: '#29444E',
900: '#183240',
950: '#0c1920'
}
}
];
constructor() {
const initialState = this.loadAppState();
this.appState.set({...initialState});
this.document.documentElement.classList.add('p-dark');
effect(
() => {
const state = this.appState();
if (!this.initialized || !state) {
this.initialized = true;
return;
}
this.saveAppState(state);
},
{allowSignalWrites: true}
);
if (isPlatformBrowser(this.platformId)) {
this.onPresetChange();
}
effect(() => {
const state = this.appState();
if (!this.initialized || !state) {
this.initialized = true;
return;
}
this.saveAppState(state);
this.onPresetChange();
}, {allowSignalWrites: true});
}
private loadAppState(): AppState {
@@ -48,4 +165,67 @@ export class AppConfigService {
localStorage.setItem(this.STORAGE_KEY, JSON.stringify(state));
}
}
private getSurfacePalette(surface: string): ColorPalette {
return this.surfaces.find(s => s.name === surface)?.palette ?? {};
}
getPresetExt(): object {
const surfacePalette = this.getSurfacePalette(this.appState().surface ?? 'neutral');
const primaryName = this.appState().primary ?? 'green';
const presetPalette = (Aura.primitive ?? {}) as Record<string, ColorPalette>;
const color = presetPalette[primaryName] ?? {};
if (primaryName === 'noir') {
return {
semantic: {
primary: {...surfacePalette},
colorScheme: {
dark: {
primary: {
color: '{primary.50}',
contrastColor: '{primary.950}',
hoverColor: '{primary.200}',
activeColor: '{primary.300}'
},
highlight: {
background: '{primary.50}',
focusBackground: '{primary.300}',
color: '{primary.950}',
focusColor: '{primary.950}'
}
}
}
}
};
}
return {
semantic: {
primary: color,
colorScheme: {
dark: {
primary: {
color: '{primary.400}',
contrastColor: '{surface.900}',
hoverColor: '{primary.300}',
activeColor: '{primary.200}'
},
highlight: {
background: 'color-mix(in srgb, {primary.400}, transparent 84%)',
focusBackground: 'color-mix(in srgb, {primary.400}, transparent 76%)',
color: 'rgba(255,255,255,.87)',
focusColor: 'rgba(255,255,255,.87)'
}
}
}
}
};
}
onPresetChange(): void {
const surfacePalette = this.getSurfacePalette(this.appState().surface ?? 'neutral');
const preset = this.getPresetExt();
$t().preset(Aura).preset(preset).surfacePalette(surfacePalette).use({useDefaultOptions: true});
}
}

View File

@@ -1,16 +1,33 @@
<div class="setup-container">
<div class="setup-wrapper">
<h1 class="app-title">BookLore</h1>
<p-card class="w-96">
<ng-template pTemplate="title">
<div class="text-center pb-2">Initial Admin Setup</div>
</ng-template>
<ng-template pTemplate="content">
<div class="flex items-center justify-center min-h-screen min-w-[100vw] overflow-hidden"
style="background: linear-gradient(60deg, var(--primary-color) 0%, #1e3a8a 100%);">
<div class="flex flex-col items-center justify-center -mt-48">
<div style="border-radius: 56px; padding: 0.3rem; background: linear-gradient(180deg, var(--primary-color) 10%, rgba(33, 150, 243, 0) 30%)">
<div class="w-full bg-surface-0 dark:bg-surface-900 py-16 px-8 sm:px-16" style="border-radius: 53px">
<div class="text-center mb-8">
<svg class="mb-8 w-16 h-16 mx-auto" viewBox="0 0 126 126" fill="var(--primary-color)" xmlns="http://www.w3.org/2000/svg">
<path
d="M59 4.79297C71.5051 11.5557 80 24.7854 80 40C80 40.5959 79.987 41.1888 79.9609 41.7783C79.8609 44.0406 81.7355 46 84 46C106.091 46 124 63.9086 124 86C124 108.091 106.091 126 84 126H10C4.47715 126 0 121.523 0 116V39.0068L0.0126953 38.9941C0.357624 25.0252 7.86506 12.8347 19 5.95215V63.832C19 64.8345 20.0676 65.4391 20.9121 64.9902L21.0771 64.8867L38.2227 52.3428C38.6819 52.0068 39.3064 52.0068 39.7656 52.3428L56.9229 64.8945L57.0879 64.998C57.9324 65.447 59 64.8423 59 63.8398V4.79297Z"/>
<path
d="M40 0C43.8745 0 47.6199 0.552381 51.1631 1.58008V50.9697L44.3926 46.0176L44.0879 45.8037C40.9061 43.6679 36.7098 43.7393 33.5957 46.0176L26.8369 50.9619V2.21875C30.9593 0.782634 35.3881 0 40 0Z"
fill="white"/>
</svg>
<div class="text-3xl font-medium mb-4">Welcome to Booklore</div>
<span class="text-muted-color text-xl">Setup Initial Admin Account</span>
</div>
<form class="flex flex-col gap-4" [formGroup]="setupForm" (ngSubmit)="onSubmit()">
<div class="flex flex-col gap-2">
<label for="name">Username</label>
<input pInputText id="name" type="text" formControlName="username" required />
<label for="username" class="text-xl font-medium">Username</label>
<input
pInputText
id="username"
name="username"
required
formControlName="username"
placeholder="Enter your username"
class="w-full md:w-[30rem]"
/>
@if (setupForm.get('username')?.invalid && setupForm.get('username')?.touched) {
<small class="text-red-500">
Username is required.
@@ -19,8 +36,16 @@
</div>
<div class="flex flex-col gap-2">
<label for="name">Name</label>
<input pInputText id="name" type="text" formControlName="name" required />
<label for="name" class="text-xl font-medium">Name</label>
<input
pInputText
id="name"
name="name"
required
formControlName="name"
placeholder="Enter your full name"
class="w-full md:w-[30rem]"
/>
@if (setupForm.get('name')?.invalid && setupForm.get('name')?.touched) {
<small class="text-red-500">
Name is required.
@@ -29,8 +54,16 @@
</div>
<div class="flex flex-col gap-2">
<label for="email">Email</label>
<input pInputText id="email" type="email" formControlName="email" required />
<label for="email" class="text-xl font-medium">Email</label>
<input
pInputText
id="email"
name="email"
required
formControlName="email"
placeholder="Enter your email"
class="w-full md:w-[30rem]"
/>
@if (setupForm.get('email')?.invalid && setupForm.get('email')?.touched) {
<small class="text-red-500">
Valid email is required.
@@ -39,8 +72,16 @@
</div>
<div class="flex flex-col gap-2">
<label for="password">Password</label>
<p-password fluid id="password" formControlName="password" [feedback]="false" required></p-password>
<label for="password" class="text-xl font-medium">Password</label>
<input
pInputText
id="password"
name="password"
required
formControlName="password"
placeholder="Enter new password"
class="w-full md:w-[30rem]"
/>
@if (setupForm.get('password')?.invalid && setupForm.get('password')?.touched) {
<small class="text-red-500">
Minimum 6 characters required.
@@ -49,11 +90,15 @@
</div>
<div class="flex flex-col gap-3 mt-4">
<p-button fluid severity="success" type="submit"
<p-button
fluid
type="submit"
[label]="loading ? 'Creating' : 'Create Admin Account'"
[disabled]="loading || setupForm.invalid"
icon="pi pi-user-plus">
icon="pi pi-user-plus"
>
</p-button>
@if (error) {
<p-message severity="error" text="{{ error }}"></p-message>
}
@@ -62,7 +107,7 @@
}
</div>
</form>
</ng-template>
</p-card>
</div>
</div>
</div>
</div>

View File

@@ -1,12 +0,0 @@
.setup-container {
@apply flex items-center justify-center min-h-screen bg-gradient-to-br from-blue-900 via-cyan-600 to-blue-400 relative;
}
.setup-wrapper {
@apply flex flex-col items-center gap-6 absolute top-1/4 transform -translate-y-1/4;
}
.app-title {
@apply text-5xl font-extrabold text-white drop-shadow-lg;
text-shadow: 0px 4px 6px rgba(0, 0, 0, 0.3);
}

View File

@@ -1,10 +1,9 @@
import {CommonModule, isPlatformBrowser} from '@angular/common';
import {Component, computed, effect, inject, OnInit, PLATFORM_ID} from '@angular/core';
import {CommonModule} from '@angular/common';
import {Component, computed, effect, inject} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {$t, updatePreset, updateSurfacePalette} from '@primeng/themes';
import {$t} from '@primeng/themes';
import Aura from '@primeng/themes/aura';
import {ButtonModule} from 'primeng/button';
import {PrimeNG} from 'primeng/config';
import {InputSwitchModule} from 'primeng/inputswitch';
import {RadioButtonModule} from 'primeng/radiobutton';
import {ToggleSwitchModule} from 'primeng/toggleswitch';
@@ -25,155 +24,24 @@ interface Palette {
host: {
class: 'config-panel hidden'
},
imports: [CommonModule, FormsModule, InputSwitchModule, ButtonModule, RadioButtonModule, ToggleSwitchModule]
imports: [
CommonModule,
FormsModule,
InputSwitchModule,
ButtonModule,
RadioButtonModule,
ToggleSwitchModule
]
})
export class ThemeConfiguratorComponent implements OnInit {
readonly config = inject(PrimeNG);
export class ThemeConfiguratorComponent {
readonly configService = inject(AppConfigService);
readonly platformId = inject(PLATFORM_ID);
readonly faviconService = inject(FaviconService);
readonly surfaces: Palette[] = [
{
name: 'slate',
palette: {
0: '#ffffff',
50: '#f8fafc',
100: '#f1f5f9',
200: '#e2e8f0',
300: '#cbd5e1',
400: '#94a3b8',
500: '#64748b',
600: '#475569',
700: '#334155',
800: '#1e293b',
900: '#0f172a',
950: '#020617'
}
},
{
name: 'gray',
palette: {
0: '#ffffff',
50: '#f9fafb',
100: '#f3f4f6',
200: '#e5e7eb',
300: '#d1d5db',
400: '#9ca3af',
500: '#6b7280',
600: '#4b5563',
700: '#374151',
800: '#1f2937',
900: '#111827',
950: '#030712'
}
},
{
name: 'zinc',
palette: {
0: '#ffffff',
50: '#fafafa',
100: '#f4f4f5',
200: '#e4e4e7',
300: '#d4d4d8',
400: '#a1a1aa',
500: '#71717a',
600: '#52525b',
700: '#3f3f46',
800: '#27272a',
900: '#18181b',
950: '#09090b'
}
},
{
name: 'neutral',
palette: {
0: '#ffffff',
50: '#fafafa',
100: '#f5f5f5',
200: '#e5e5e5',
300: '#d4d4d4',
400: '#a3a3a3',
500: '#737373',
600: '#525252',
700: '#404040',
800: '#262626',
900: '#171717',
950: '#0a0a0a'
}
},
{
name: 'stone',
palette: {
0: '#ffffff',
50: '#fafaf9',
100: '#f5f5f4',
200: '#e7e5e4',
300: '#d6d3d1',
400: '#a8a29e',
500: '#78716c',
600: '#57534e',
700: '#44403c',
800: '#292524',
900: '#1c1917',
950: '#0c0a09'
}
},
{
name: 'soho',
palette: {
0: '#ffffff',
50: '#ececec',
100: '#dedfdf',
200: '#c4c4c6',
300: '#adaeb0',
400: '#97979b',
500: '#7f8084',
600: '#6a6b70',
700: '#55565b',
800: '#3f4046',
900: '#2c2c34',
950: '#16161d'
}
},
{
name: 'viva',
palette: {
0: '#ffffff',
50: '#f3f3f3',
100: '#e7e7e8',
200: '#cfd0d0',
300: '#b7b8b9',
400: '#9fa1a1',
500: '#87898a',
600: '#6e7173',
700: '#565a5b',
800: '#3e4244',
900: '#262b2c',
950: '#0e1315'
}
},
{
name: 'ocean',
palette: {
0: '#ffffff',
50: '#fbfcfc',
100: '#F7F9F8',
200: '#EFF3F2',
300: '#DADEDD',
400: '#B1B7B6',
500: '#828787',
600: '#5F7274',
700: '#415B61',
800: '#29444E',
900: '#183240',
950: '#0c1920'
}
}
];
readonly surfaces = this.configService.surfaces;
readonly selectedPrimaryColor = computed(() => this.configService.appState().primary);
readonly selectedSurfaceColor = computed(() => this.configService.appState().surface);
readonly faviconColor = computed(() => {
const name = this.selectedPrimaryColor() ?? 'green';
const presetPalette = (Aura.primitive ?? {}) as Record<string, ColorPalette>;
@@ -196,84 +64,11 @@ export class ThemeConfiguratorComponent implements OnInit {
);
});
ngOnInit(): void {
if (isPlatformBrowser(this.platformId)) {
this.onPresetChange();
}
}
getPresetExt(): object {
const color = this.primaryColors().find(c => c.name === this.selectedPrimaryColor());
const surface = this.surfaces.find(s => s.name === this.selectedSurfaceColor());
if (!color) return {};
if (color.name === 'noir') {
return {
semantic: {
primary: {...(surface?.palette ?? {})},
colorScheme: {
dark: {
primary: {
color: '{primary.50}',
contrastColor: '{primary.950}',
hoverColor: '{primary.200}',
activeColor: '{primary.300}'
},
highlight: {
background: '{primary.50}',
focusBackground: '{primary.300}',
color: '{primary.950}',
focusColor: '{primary.950}'
}
}
}
}
};
}
return {
semantic: {
primary: color.palette,
colorScheme: {
dark: {
primary: {
color: '{primary.400}',
contrastColor: '{surface.900}',
hoverColor: '{primary.300}',
activeColor: '{primary.200}'
},
highlight: {
background: 'color-mix(in srgb, {primary.400}, transparent 84%)',
focusBackground: 'color-mix(in srgb, {primary.400}, transparent 76%)',
color: 'rgba(255,255,255,.87)',
focusColor: 'rgba(255,255,255,.87)'
}
}
}
}
};
}
updateColors(event: Event, type: 'primary' | 'surface', color: { name: string; palette?: ColorPalette }) {
this.configService.appState.update((state) => ({
...state,
[type]: color.name
}));
this.applyTheme(type, color);
event.stopPropagation();
}
applyTheme(type: 'primary' | 'surface', color: { name: string; palette?: ColorPalette }) {
if (type === 'primary') {
updatePreset(this.getPresetExt());
} else if (type === 'surface') {
updateSurfacePalette(color.palette ?? {});
}
}
onPresetChange(): void {
const surface = this.surfaces.find(s => s.name === this.selectedSurfaceColor());
const surfacePalette = surface?.palette ?? {};
$t().preset(Aura).preset(this.getPresetExt()).surfacePalette(surfacePalette).use({useDefaultOptions: true});
}
}

View File

@@ -19,11 +19,6 @@ import {initializeAuthFactory} from './app/auth-initializer';
bootstrapApplication(AppComponent, {
providers: [
{
provide: APP_INITIALIZER,
useFactory: themeInitializer,
multi: true
},
{
provide: APP_INITIALIZER,
useFactory: websocketInitializer,
@@ -57,10 +52,3 @@ bootstrapApplication(AppComponent, {
})
]
}).catch(err => console.error(err));
export function themeInitializer(): () => void {
return () => {
document.documentElement.classList.add('p-dark');
document.body.classList.add('p-dark');
};
}