import { DeesElement, customElement, html, css, cssManager, property, type TemplateResult, } from '@design.estate/dees-element'; declare global { interface HTMLElementTagNameMap { 'sz-login-view': SzLoginView; } } @customElement('sz-login-view') export class SzLoginView extends DeesElement { public static demo = () => html`
`; public static demoGroups = ['Auth & Settings']; @property({ type: Boolean }) public accessor loading: boolean = false; @property({ type: String }) public accessor error: string = ''; @property({ type: String }) public accessor title: string = 'serve.zone'; @property({ type: String }) public accessor subtitle: string = 'Sign in to your onebox'; public static styles = [ cssManager.defaultStyles, css` :host { display: flex; align-items: center; justify-content: center; min-height: 100vh; width: 100%; background: ${cssManager.bdTheme('#f4f4f5', '#09090b')}; } .login-container { width: 100%; max-width: 400px; padding: 24px; } .login-card { background: ${cssManager.bdTheme('#ffffff', '#18181b')}; border: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')}; border-radius: 12px; padding: 32px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); } .logo-section { text-align: center; margin-bottom: 32px; } .logo { width: 64px; height: 64px; background: ${cssManager.bdTheme('#18181b', '#fafafa')}; border-radius: 12px; display: flex; align-items: center; justify-content: center; margin: 0 auto 16px; } .logo svg { width: 36px; height: 36px; color: ${cssManager.bdTheme('#fafafa', '#18181b')}; } .title { font-size: 24px; font-weight: 700; color: ${cssManager.bdTheme('#18181b', '#fafafa')}; margin-bottom: 4px; } .subtitle { font-size: 14px; color: ${cssManager.bdTheme('#71717a', '#a1a1aa')}; } .form { display: flex; flex-direction: column; gap: 20px; } .form-group { display: flex; flex-direction: column; gap: 6px; } .form-label { font-size: 14px; font-weight: 500; color: ${cssManager.bdTheme('#18181b', '#fafafa')}; } .form-input { width: 100%; padding: 12px 14px; background: ${cssManager.bdTheme('#ffffff', '#09090b')}; border: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')}; border-radius: 8px; font-size: 14px; color: ${cssManager.bdTheme('#18181b', '#fafafa')}; outline: none; transition: border-color 200ms ease, box-shadow 200ms ease; box-sizing: border-box; } .form-input:focus { border-color: ${cssManager.bdTheme('#3b82f6', '#60a5fa')}; box-shadow: 0 0 0 3px ${cssManager.bdTheme('rgba(59, 130, 246, 0.1)', 'rgba(96, 165, 250, 0.1)')}; } .form-input::placeholder { color: ${cssManager.bdTheme('#a1a1aa', '#52525b')}; } .form-input.error { border-color: ${cssManager.bdTheme('#ef4444', '#f87171')}; } .error-message { display: flex; align-items: center; gap: 8px; padding: 12px 14px; background: ${cssManager.bdTheme('#fef2f2', 'rgba(239, 68, 68, 0.1)')}; border: 1px solid ${cssManager.bdTheme('#fecaca', 'rgba(239, 68, 68, 0.2)')}; border-radius: 8px; font-size: 14px; color: ${cssManager.bdTheme('#dc2626', '#f87171')}; } .error-message svg { width: 18px; height: 18px; flex-shrink: 0; } .submit-button { width: 100%; padding: 12px 20px; background: ${cssManager.bdTheme('#18181b', '#fafafa')}; border: none; border-radius: 8px; font-size: 14px; font-weight: 600; color: ${cssManager.bdTheme('#fafafa', '#18181b')}; cursor: pointer; transition: opacity 200ms ease, transform 200ms ease; display: flex; align-items: center; justify-content: center; gap: 8px; } .submit-button:hover:not(:disabled) { opacity: 0.9; } .submit-button:active:not(:disabled) { transform: scale(0.98); } .submit-button:disabled { opacity: 0.6; cursor: not-allowed; } .spinner { width: 18px; height: 18px; border: 2px solid transparent; border-top-color: currentColor; border-radius: 50%; animation: spin 0.8s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } } .footer { margin-top: 24px; text-align: center; font-size: 13px; color: ${cssManager.bdTheme('#71717a', '#a1a1aa')}; } .footer a { color: ${cssManager.bdTheme('#3b82f6', '#60a5fa')}; text-decoration: none; } .footer a:hover { text-decoration: underline; } `, ]; public render(): TemplateResult { return html`
${this.title}
${this.subtitle}
${this.error ? html`
${this.error}
` : ''}
`; } private handleSubmit(e: Event) { e.preventDefault(); const usernameInput = this.shadowRoot?.getElementById('username') as HTMLInputElement; const passwordInput = this.shadowRoot?.getElementById('password') as HTMLInputElement; if (!usernameInput || !passwordInput) return; const username = usernameInput.value.trim(); const password = passwordInput.value; if (!username || !password) { this.error = 'Please enter both username and password'; return; } this.error = ''; this.dispatchEvent(new CustomEvent('login', { detail: { username, password }, bubbles: true, composed: true, })); } public clearForm() { const usernameInput = this.shadowRoot?.getElementById('username') as HTMLInputElement; const passwordInput = this.shadowRoot?.getElementById('password') as HTMLInputElement; if (usernameInput) usernameInput.value = ''; if (passwordInput) passwordInput.value = ''; this.error = ''; } public focusUsername() { const usernameInput = this.shadowRoot?.getElementById('username') as HTMLInputElement; if (usernameInput) usernameInput.focus(); } }