unf auth screen

This commit is contained in:
Peter Steinberger 2025-06-25 04:21:43 +02:00
parent 59aacd8707
commit ca4ebeba15
2 changed files with 22 additions and 104 deletions

View file

@ -2,9 +2,7 @@ import { html, LitElement } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import type { AuthClient } from '../services/auth-client.js';
import { responsiveObserver } from '../utils/responsive-utils.js';
import { AppSettings } from './app-settings.js';
import './terminal-icon.js';
import './auth-quick-keys.js';
@customElement('auth-login')
export class AuthLogin extends LitElement {
@ -25,27 +23,18 @@ export class AuthLogin extends LitElement {
disallowUserPassword: false,
noAuth: false,
};
@state() private useDirectKeyboard = false;
@state() private isMobile = false;
@state() private isKeyboardFocused = false;
private unsubscribeResponsive?: () => void;
async connectedCallback() {
super.connectedCallback();
console.log('🔌 Auth login component connected');
// Load preferences
const preferences = AppSettings.getPreferences();
this.useDirectKeyboard = preferences.useDirectKeyboard;
// Subscribe to responsive changes
this.unsubscribeResponsive = responsiveObserver.subscribe((state) => {
this.isMobile = state.isMobile;
});
// Listen for preference changes
window.addEventListener('app-preferences-changed', this.handlePreferencesChanged);
await this.loadUserInfo();
}
@ -54,14 +43,8 @@ export class AuthLogin extends LitElement {
if (this.unsubscribeResponsive) {
this.unsubscribeResponsive();
}
window.removeEventListener('app-preferences-changed', this.handlePreferencesChanged);
}
private handlePreferencesChanged = (e: Event) => {
const event = e as CustomEvent;
this.useDirectKeyboard = event.detail.useDirectKeyboard;
};
private async loadUserInfo() {
try {
// Load auth configuration first
@ -159,35 +142,6 @@ export class AuthLogin extends LitElement {
this.dispatchEvent(new CustomEvent('show-ssh-key-manager'));
}
private handleKeyCapture = (e: KeyboardEvent) => {
if (this.loading) return;
e.preventDefault();
if (e.key === 'Enter') {
this.handlePasswordLogin(e);
} else if (e.key === 'Backspace') {
this.loginPassword = this.loginPassword.slice(0, -1);
} else if (e.key === 'Escape') {
this.loginPassword = '';
} else if (e.key.length === 1) {
this.loginPassword += e.key;
}
};
private handleQuickKey = (key: string) => {
if (this.loading) return;
this.loginPassword += key;
};
private handleFocus = () => {
this.isKeyboardFocused = true;
};
private handleBlur = () => {
this.isKeyboardFocused = false;
};
render() {
console.log(
'🔍 Rendering auth login',
@ -201,12 +155,12 @@ export class AuthLogin extends LitElement {
<div class="auth-container">
<div class="w-full max-w-sm">
<div class="auth-header">
<div class="flex flex-col items-center gap-1 sm:gap-3 mb-2 sm:mb-8">
<div class="flex flex-col items-center gap-2 sm:gap-3 mb-4 sm:mb-8">
<terminal-icon
size="${this.isMobile ? '40' : '56'}"
size="${this.isMobile ? '48' : '56'}"
style="filter: drop-shadow(0 0 15px rgba(124, 230, 161, 0.4));"
></terminal-icon>
<h2 class="auth-title text-xl sm:text-3xl mt-0 sm:mt-2">VibeTunnel</h2>
<h2 class="auth-title text-2xl sm:text-3xl mt-1 sm:mt-2">VibeTunnel</h2>
<p class="auth-subtitle text-xs sm:text-sm">Please authenticate to continue</p>
</div>
</div>
@ -254,9 +208,9 @@ export class AuthLogin extends LitElement {
!this.authConfig.disallowUserPassword
? html`
<!-- Password Login Section (Primary) -->
<div class="p-4 sm:p-8">
<div class="flex flex-col items-center mb-3 sm:mb-6">
<div class="w-14 h-14 sm:w-20 sm:h-20 rounded-full mb-2 sm:mb-3 overflow-hidden" style="box-shadow: 0 0 20px rgba(124, 230, 161, 0.3);">
<div class="p-5 sm:p-8">
<div class="flex flex-col items-center mb-4 sm:mb-6">
<div class="w-24 h-24 sm:w-28 sm:h-28 rounded-full mb-3 sm:mb-4 overflow-hidden" style="box-shadow: 0 0 25px rgba(124, 230, 161, 0.3);">
${
this.userAvatar
? html`
@ -270,71 +224,35 @@ export class AuthLogin extends LitElement {
`
: html`
<div class="w-full h-full bg-dark-bg-secondary flex items-center justify-center">
<svg class="w-7 h-7 sm:w-10 sm:h-10 text-dark-text-muted" fill="currentColor" viewBox="0 0 20 20">
<svg class="w-12 h-12 sm:w-14 sm:h-14 text-dark-text-muted" fill="currentColor" viewBox="0 0 20 20">
<path d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" />
</svg>
</div>
`
}
</div>
<p class="text-dark-text text-sm sm:text-lg font-medium">
<p class="text-dark-text text-base sm:text-lg font-medium">
Welcome back, ${this.currentUserId || '...'}
</p>
</div>
<form @submit=${this.handlePasswordLogin} class="space-y-3">
<div>
${
this.useDirectKeyboard
? html`
<!-- Direct keyboard capture -->
<div
class="password-capture-area bg-[#121212] border ${this.isKeyboardFocused ? 'border-accent-green shadow-glow-green-sm' : 'border-dark-border'} rounded-lg px-4 py-3 text-dark-text w-full transition-all duration-200 ease-in-out hover:border-accent-green-darker cursor-text min-h-[48px] flex items-center"
tabindex="0"
@keydown=${this.handleKeyCapture}
@focus=${this.handleFocus}
@blur=${this.handleBlur}
data-testid="password-capture"
>
<span class="${this.loginPassword ? 'text-dark-text' : 'text-dark-text-muted'} text-sm">
${
this.loginPassword
? '•'.repeat(this.loginPassword.length)
: this.isKeyboardFocused
? 'Type your password...'
: 'Click to enter password'
}
</span>
</div>
${
this.isMobile
? html`
<div class="mt-2">
<auth-quick-keys .onKeyPress=${this.handleQuickKey}></auth-quick-keys>
</div>
`
: ''
}
`
: html`
<!-- Traditional input field -->
<input
type="password"
class="input-field"
data-testid="password-input"
placeholder="System Password"
.value=${this.loginPassword}
@input=${(e: Event) => {
this.loginPassword = (e.target as HTMLInputElement).value;
}}
?disabled=${this.loading}
required
/>
`
}
<input
type="password"
class="input-field"
data-testid="password-input"
placeholder="System Password"
.value=${this.loginPassword}
@input=${(e: Event) => {
this.loginPassword = (e.target as HTMLInputElement).value;
}}
?disabled=${this.loading}
required
/>
</div>
<button
type="submit"
class="btn-primary w-full py-2.5 sm:py-4 mt-2 text-sm sm:text-base"
class="btn-primary w-full py-3 sm:py-4 mt-2"
data-testid="password-submit"
?disabled=${this.loading || !this.loginPassword}
>

View file

@ -168,7 +168,7 @@
@media (max-width: 768px) {
.auth-container {
@apply py-4; /* Reduced vertical padding on mobile */
@apply py-6; /* Comfortable vertical padding on mobile */
min-height: 100vh;
min-height: 100dvh;
/* Prevent scrolling - content should fit */