feat: add pseudo-authorization with code word
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
User must enter code word "пупырка" to access the app. Auth state persisted in localStorage. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@ -1,14 +1,116 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, signal } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { ToastModule } from 'primeng/toast';
|
||||
import { AppLayoutComponent } from './components/app-layout/app-layout.component';
|
||||
|
||||
const AUTH_KEY = 'test-x6-auth';
|
||||
const CODE_WORD = 'пупырка';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
standalone: true,
|
||||
imports: [ToastModule, AppLayoutComponent],
|
||||
imports: [FormsModule, ToastModule, AppLayoutComponent],
|
||||
template: `
|
||||
@if (authorized()) {
|
||||
<p-toast />
|
||||
<app-layout />
|
||||
} @else {
|
||||
<div class="login-wrapper">
|
||||
<div class="login-card">
|
||||
<h2>Детальная схема связей</h2>
|
||||
<p>Введите кодовое слово для входа</p>
|
||||
<input
|
||||
type="password"
|
||||
[(ngModel)]="inputValue"
|
||||
(keydown.enter)="tryLogin()"
|
||||
placeholder="Кодовое слово"
|
||||
[class.error]="showError()"
|
||||
autofocus
|
||||
/>
|
||||
@if (showError()) {
|
||||
<span class="error-text">Неверное кодовое слово</span>
|
||||
}
|
||||
<button (click)="tryLogin()">Войти</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
`,
|
||||
styles: `
|
||||
.login-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
.login-card {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 32px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
|
||||
text-align: center;
|
||||
width: 320px;
|
||||
}
|
||||
.login-card h2 {
|
||||
margin: 0 0 8px;
|
||||
font-size: 18px;
|
||||
color: #333;
|
||||
}
|
||||
.login-card p {
|
||||
margin: 0 0 20px;
|
||||
color: #888;
|
||||
font-size: 13px;
|
||||
}
|
||||
.login-card input {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
outline: none;
|
||||
box-sizing: border-box;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
.login-card input:focus {
|
||||
border-color: #4096ff;
|
||||
}
|
||||
.login-card input.error {
|
||||
border-color: #ff4d4f;
|
||||
}
|
||||
.error-text {
|
||||
display: block;
|
||||
color: #ff4d4f;
|
||||
font-size: 12px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
.login-card button {
|
||||
margin-top: 16px;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
background: #4096ff;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
.login-card button:hover {
|
||||
background: #1677ff;
|
||||
}
|
||||
`,
|
||||
})
|
||||
export class AppComponent {}
|
||||
export class AppComponent {
|
||||
authorized = signal(localStorage.getItem(AUTH_KEY) === 'true');
|
||||
showError = signal(false);
|
||||
inputValue = '';
|
||||
|
||||
tryLogin() {
|
||||
if (this.inputValue.trim().toLowerCase() === CODE_WORD) {
|
||||
localStorage.setItem(AUTH_KEY, 'true');
|
||||
this.authorized.set(true);
|
||||
} else {
|
||||
this.showError.set(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user