feat: login and register, style is not ready
This commit is contained in:
+1
-1
@@ -1,2 +1,2 @@
|
|||||||
<app-toolbar />
|
<app-toolbar />
|
||||||
<router-outlet />
|
<router-outlet />
|
||||||
+1
-1
@@ -10,7 +10,7 @@ import { ThemeService } from './services/theme.service';
|
|||||||
styleUrl: './app.css'
|
styleUrl: './app.css'
|
||||||
})
|
})
|
||||||
export class App implements OnInit {
|
export class App implements OnInit {
|
||||||
constructor(private readonly themeService: ThemeService) {}
|
constructor(private readonly themeService: ThemeService) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.themeService.initTheme();
|
this.themeService.initTheme();
|
||||||
|
|||||||
@@ -7,18 +7,18 @@
|
|||||||
<input id="username" type="text" class="dialog-input" formControlName="username" placeholder="Username"
|
<input id="username" type="text" class="dialog-input" formControlName="username" placeholder="Username"
|
||||||
[disabled]="isLoading" />
|
[disabled]="isLoading" />
|
||||||
@if (loginForm.get('username')?.invalid && loginForm.get('username')?.touched) {
|
@if (loginForm.get('username')?.invalid && loginForm.get('username')?.touched) {
|
||||||
<small class="text-danger">Username must be at least 3 characters</small>
|
<small class="text-danger">Username must be at least 3 characters</small>
|
||||||
}
|
}
|
||||||
|
|
||||||
<label for="password" class="sr-only">Password</label>
|
<label for="password" class="sr-only">Password</label>
|
||||||
<input id="password" type="password" class="dialog-input" formControlName="password" placeholder="Password"
|
<input id="password" type="password" class="dialog-input" formControlName="password" placeholder="Password"
|
||||||
[disabled]="isLoading" />
|
[disabled]="isLoading" />
|
||||||
@if (loginForm.get('password')?.invalid && loginForm.get('password')?.touched) {
|
@if (loginForm.get('password')?.invalid && loginForm.get('password')?.touched) {
|
||||||
<small class="text-danger">Password must be at least 6 characters</small>
|
<small class="text-danger">Password must be at least 6 characters</small>
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (errorMessage) {
|
@if (errorMessage) {
|
||||||
<div class="error-banner">{{ errorMessage }}</div>
|
<div class="error-banner">{{ errorMessage }}</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="dialog-actions">
|
<div class="dialog-actions">
|
||||||
@@ -26,11 +26,11 @@
|
|||||||
<button type="button" class="dialog-btn" (click)="closeDialog()">Cancel</button>
|
<button type="button" class="dialog-btn" (click)="closeDialog()">Cancel</button>
|
||||||
<button type="button" class="dialog-btn" (click)="onSubmit()" [disabled]="isLoading || loginForm.invalid">
|
<button type="button" class="dialog-btn" (click)="onSubmit()" [disabled]="isLoading || loginForm.invalid">
|
||||||
@if (isLoading) {
|
@if (isLoading) {
|
||||||
<span class="spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>
|
<span class="spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>
|
||||||
}
|
}
|
||||||
Login
|
Login
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -6,26 +6,26 @@
|
|||||||
<input id="username" type="text" class="dialog-input" formControlName="username" placeholder="Username"
|
<input id="username" type="text" class="dialog-input" formControlName="username" placeholder="Username"
|
||||||
[disabled]="isLoading" />
|
[disabled]="isLoading" />
|
||||||
@if (registerForm.get('username')?.invalid && registerForm.get('username')?.touched) {
|
@if (registerForm.get('username')?.invalid && registerForm.get('username')?.touched) {
|
||||||
<small class="text-danger">Username must be at least 3 characters</small>
|
<small class="text-danger">Username must be at least 3 characters</small>
|
||||||
}
|
}
|
||||||
|
|
||||||
<input id="email" type="email" class="dialog-input" formControlName="email" placeholder="Email"
|
<input id="email" type="email" class="dialog-input" formControlName="email" placeholder="Email"
|
||||||
[disabled]="isLoading" />
|
[disabled]="isLoading" />
|
||||||
@if (registerForm.get('email')?.invalid && registerForm.get('email')?.touched) {
|
@if (registerForm.get('email')?.invalid && registerForm.get('email')?.touched) {
|
||||||
<small class="text-danger">Please enter a valid email</small>
|
<small class="text-danger">Please enter a valid email</small>
|
||||||
}
|
}
|
||||||
|
|
||||||
<input id="password" type="password" class="dialog-input" formControlName="password" placeholder="Password"
|
<input id="password" type="password" class="dialog-input" formControlName="password" placeholder="Password"
|
||||||
[disabled]="isLoading" />
|
[disabled]="isLoading" />
|
||||||
@if (registerForm.get('password')?.invalid && registerForm.get('password')?.touched) {
|
@if (registerForm.get('password')?.invalid && registerForm.get('password')?.touched) {
|
||||||
<small class="text-danger">Password must be at least 6 characters</small>
|
<small class="text-danger">Password must be at least 6 characters</small>
|
||||||
}
|
}
|
||||||
|
|
||||||
<input id="confirmPassword" type="password" class="dialog-input" formControlName="confirmPassword"
|
<input id="confirmPassword" type="password" class="dialog-input" formControlName="confirmPassword"
|
||||||
placeholder="Confirm Password" [disabled]="isLoading" />
|
placeholder="Confirm Password" [disabled]="isLoading" />
|
||||||
|
|
||||||
@if (errorMessage) {
|
@if (errorMessage) {
|
||||||
<div class="error-banner">{{ errorMessage }}</div>
|
<div class="error-banner">{{ errorMessage }}</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="dialog-actions">
|
<div class="dialog-actions">
|
||||||
@@ -33,11 +33,11 @@
|
|||||||
<button type="button" class="dialog-btn" (click)="closeDialog()">Cancel</button>
|
<button type="button" class="dialog-btn" (click)="closeDialog()">Cancel</button>
|
||||||
<button type="button" class="dialog-btn" (click)="onSubmit()" [disabled]="isLoading || registerForm.invalid">
|
<button type="button" class="dialog-btn" (click)="onSubmit()" [disabled]="isLoading || registerForm.invalid">
|
||||||
@if (isLoading) {
|
@if (isLoading) {
|
||||||
<span class="spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>
|
<span class="spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>
|
||||||
}
|
}
|
||||||
Register
|
Register
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -7,17 +7,17 @@
|
|||||||
{{ isDarkMode ? 'Light mode' : 'Dark mode' }}
|
{{ isDarkMode ? 'Light mode' : 'Dark mode' }}
|
||||||
</button>
|
</button>
|
||||||
@if (currentUser; as user) {
|
@if (currentUser; as user) {
|
||||||
<div class="d-flex align-items-center gap-2">
|
<div class="d-flex align-items-center gap-2">
|
||||||
<span style="color:var(--bb-title);font-weight:700">{{ user.username }}</span>
|
<span style="color:var(--bb-title);font-weight:700">{{ user.username }}</span>
|
||||||
<button class="dialog-btn" (click)="logout()">Logout</button>
|
<button class="dialog-btn" (click)="logout()">Logout</button>
|
||||||
</div>
|
</div>
|
||||||
} @else {
|
} @else {
|
||||||
<button class="dialog-btn" (click)="openLoginDialog()">
|
<button class="dialog-btn" (click)="openLoginDialog()">
|
||||||
Login
|
Login
|
||||||
</button>
|
</button>
|
||||||
<button class="dialog-btn" (click)="openRegisterDialog()">
|
<button class="dialog-btn" (click)="openRegisterDialog()">
|
||||||
Register
|
Register
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -25,9 +25,9 @@
|
|||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
@if (showLoginDialog) {
|
@if (showLoginDialog) {
|
||||||
<app-login-dialog (onClose)="closeLoginDialog()" (onSuccess)="onLoginSuccess()" />
|
<app-login-dialog (onClose)="closeLoginDialog()" (onSuccess)="onLoginSuccess()" />
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (showRegisterDialog) {
|
@if (showRegisterDialog) {
|
||||||
<app-register-dialog (onClose)="closeRegisterDialog()" (onSuccess)="onRegisterSuccess()" />
|
<app-register-dialog (onClose)="closeRegisterDialog()" (onSuccess)="onRegisterSuccess()" />
|
||||||
}
|
}
|
||||||
@@ -123,7 +123,7 @@ export class WelcomeComponent implements OnInit, OnDestroy {
|
|||||||
this.generateBackgroundBuildings();
|
this.generateBackgroundBuildings();
|
||||||
this.generateWindowsForAllBuildings();
|
this.generateWindowsForAllBuildings();
|
||||||
this.startWindowFlicker();
|
this.startWindowFlicker();
|
||||||
|
|
||||||
// Show speech bubble after 5 seconds
|
// Show speech bubble after 5 seconds
|
||||||
this.speechBubbleTimeoutId = setTimeout(() => {
|
this.speechBubbleTimeoutId = setTimeout(() => {
|
||||||
this.showSpeechBubble = true;
|
this.showSpeechBubble = true;
|
||||||
@@ -245,7 +245,7 @@ export class WelcomeComponent implements OnInit, OnDestroy {
|
|||||||
this.showMeatEmoji = true;
|
this.showMeatEmoji = true;
|
||||||
this.showHappyBubble = false;
|
this.showHappyBubble = false;
|
||||||
this.showSecondSpeechBubble = true;
|
this.showSecondSpeechBubble = true;
|
||||||
|
|
||||||
// Reset meat position
|
// Reset meat position
|
||||||
this.meatX = window.innerWidth / 2 - 100;
|
this.meatX = window.innerWidth / 2 - 100;
|
||||||
this.meatY = window.innerHeight / 2 + 150;
|
this.meatY = window.innerHeight / 2 + 150;
|
||||||
@@ -257,7 +257,7 @@ export class WelcomeComponent implements OnInit, OnDestroy {
|
|||||||
this.showHappyBubble = false;
|
this.showHappyBubble = false;
|
||||||
this.showMeatEmoji = false;
|
this.showMeatEmoji = false;
|
||||||
this.bubbleMessage = 'meow';
|
this.bubbleMessage = 'meow';
|
||||||
|
|
||||||
if (this.zoomTimeoutId) {
|
if (this.zoomTimeoutId) {
|
||||||
clearTimeout(this.zoomTimeoutId);
|
clearTimeout(this.zoomTimeoutId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,19 +5,19 @@ export type AuthDialogState = 'login' | 'register' | null;
|
|||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class AuthDialogService {
|
export class AuthDialogService {
|
||||||
private readonly dialogStateSubject = new BehaviorSubject<AuthDialogState>(null);
|
private readonly dialogStateSubject = new BehaviorSubject<AuthDialogState>(null);
|
||||||
|
|
||||||
readonly dialogState$ = this.dialogStateSubject.asObservable();
|
readonly dialogState$ = this.dialogStateSubject.asObservable();
|
||||||
|
|
||||||
openLogin(): void {
|
openLogin(): void {
|
||||||
this.dialogStateSubject.next('login');
|
this.dialogStateSubject.next('login');
|
||||||
}
|
}
|
||||||
|
|
||||||
openRegister(): void {
|
openRegister(): void {
|
||||||
this.dialogStateSubject.next('register');
|
this.dialogStateSubject.next('register');
|
||||||
}
|
}
|
||||||
|
|
||||||
close(): void {
|
close(): void {
|
||||||
this.dialogStateSubject.next(null);
|
this.dialogStateSubject.next(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,32 +3,32 @@ import { BehaviorSubject } from 'rxjs';
|
|||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class ThemeService {
|
export class ThemeService {
|
||||||
private readonly darkModeSubject = new BehaviorSubject<boolean>(false);
|
private readonly darkModeSubject = new BehaviorSubject<boolean>(false);
|
||||||
|
|
||||||
readonly darkMode$ = this.darkModeSubject.asObservable();
|
readonly darkMode$ = this.darkModeSubject.asObservable();
|
||||||
|
|
||||||
initTheme(): void {
|
initTheme(): void {
|
||||||
const savedTheme = localStorage.getItem('theme');
|
const savedTheme = localStorage.getItem('theme');
|
||||||
this.applyDarkMode(savedTheme === 'dark');
|
this.applyDarkMode(savedTheme === 'dark');
|
||||||
}
|
|
||||||
|
|
||||||
toggleTheme(): void {
|
|
||||||
this.applyDarkMode(!this.darkModeSubject.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
setDarkMode(isDarkMode: boolean): void {
|
|
||||||
this.applyDarkMode(isDarkMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
private applyDarkMode(isDarkMode: boolean): void {
|
|
||||||
if (isDarkMode) {
|
|
||||||
document.documentElement.setAttribute('data-theme', 'dark');
|
|
||||||
localStorage.setItem('theme', 'dark');
|
|
||||||
} else {
|
|
||||||
document.documentElement.removeAttribute('data-theme');
|
|
||||||
localStorage.removeItem('theme');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.darkModeSubject.next(isDarkMode);
|
toggleTheme(): void {
|
||||||
}
|
this.applyDarkMode(!this.darkModeSubject.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
setDarkMode(isDarkMode: boolean): void {
|
||||||
|
this.applyDarkMode(isDarkMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private applyDarkMode(isDarkMode: boolean): void {
|
||||||
|
if (isDarkMode) {
|
||||||
|
document.documentElement.setAttribute('data-theme', 'dark');
|
||||||
|
localStorage.setItem('theme', 'dark');
|
||||||
|
} else {
|
||||||
|
document.documentElement.removeAttribute('data-theme');
|
||||||
|
localStorage.removeItem('theme');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.darkModeSubject.next(isDarkMode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user