import { DeesElement, customElement, html, css, cssManager, property, type TemplateResult, } from '@design.estate/dees-element'; declare global { interface HTMLElementTagNameMap { 'sz-settings-view': SzSettingsView; } } export interface ISettings { darkMode: boolean; cloudflareToken: string; cloudflareZoneId: string; autoRenewCerts: boolean; renewalThreshold: number; acmeEmail: string; httpPort: number; httpsPort: number; forceHttps: boolean; } @customElement('sz-settings-view') export class SzSettingsView extends DeesElement { public static demo = () => html`
`; public static demoGroups = ['Auth & Settings']; @property({ type: Object }) public accessor settings: ISettings = { darkMode: false, cloudflareToken: '', cloudflareZoneId: '', autoRenewCerts: true, renewalThreshold: 30, acmeEmail: '', httpPort: 80, httpsPort: 443, forceHttps: true, }; @property({ type: String }) public accessor currentUser: string = ''; public static styles = [ cssManager.defaultStyles, css` :host { display: block; } .section { background: ${cssManager.bdTheme('#ffffff', '#09090b')}; border: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')}; border-radius: 8px; padding: 20px; margin-bottom: 24px; } .section-header { margin-bottom: 16px; } .section-title { font-size: 16px; font-weight: 600; color: ${cssManager.bdTheme('#18181b', '#fafafa')}; } .section-subtitle { font-size: 13px; color: ${cssManager.bdTheme('#71717a', '#a1a1aa')}; margin-top: 2px; } .form-group { margin-bottom: 16px; } .form-group:last-child { margin-bottom: 0; } .form-row { display: flex; justify-content: space-between; align-items: center; padding: 12px 0; border-bottom: 1px solid ${cssManager.bdTheme('#f4f4f5', '#27272a')}; } .form-row:last-child { border-bottom: none; } .form-label-group { display: flex; flex-direction: column; gap: 2px; } .form-label { font-size: 14px; font-weight: 500; color: ${cssManager.bdTheme('#18181b', '#fafafa')}; } .form-hint { font-size: 12px; color: ${cssManager.bdTheme('#71717a', '#a1a1aa')}; } .input-group { display: flex; flex-direction: column; gap: 8px; } .input-row { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; } input[type="text"], input[type="password"], input[type="email"], input[type="number"] { width: 100%; padding: 8px 12px; background: ${cssManager.bdTheme('#ffffff', '#09090b')}; border: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')}; border-radius: 6px; font-size: 14px; color: ${cssManager.bdTheme('#18181b', '#fafafa')}; outline: none; transition: border-color 200ms ease; box-sizing: border-box; } input:focus { border-color: ${cssManager.bdTheme('#3b82f6', '#60a5fa')}; } input::placeholder { color: ${cssManager.bdTheme('#a1a1aa', '#52525b')}; } .toggle-switch { position: relative; width: 44px; height: 24px; background: ${cssManager.bdTheme('#e4e4e7', '#27272a')}; border-radius: 9999px; cursor: pointer; transition: background 200ms ease; } .toggle-switch.active { background: ${cssManager.bdTheme('#2563eb', '#3b82f6')}; } .toggle-switch::after { content: ''; position: absolute; top: 2px; left: 2px; width: 20px; height: 20px; background: white; border-radius: 50%; transition: transform 200ms ease; } .toggle-switch.active::after { transform: translateX(20px); } .password-section { margin-top: 16px; padding-top: 16px; border-top: 1px solid ${cssManager.bdTheme('#f4f4f5', '#27272a')}; } .password-title { font-size: 14px; font-weight: 600; color: ${cssManager.bdTheme('#18181b', '#fafafa')}; margin-bottom: 12px; } .password-fields { display: flex; flex-direction: column; gap: 12px; } .field-label { font-size: 13px; color: ${cssManager.bdTheme('#71717a', '#a1a1aa')}; margin-bottom: 4px; } .actions { display: flex; justify-content: flex-end; gap: 12px; padding-top: 16px; border-top: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')}; margin-top: 24px; } .button { padding: 10px 20px; border-radius: 6px; font-size: 14px; font-weight: 500; cursor: pointer; transition: all 200ms ease; } .button.secondary { background: ${cssManager.bdTheme('#ffffff', '#09090b')}; border: 1px solid ${cssManager.bdTheme('#e4e4e7', '#27272a')}; color: ${cssManager.bdTheme('#18181b', '#fafafa')}; } .button.secondary:hover { background: ${cssManager.bdTheme('#f4f4f5', '#18181b')}; } .button.primary { background: ${cssManager.bdTheme('#18181b', '#fafafa')}; border: none; color: ${cssManager.bdTheme('#fafafa', '#18181b')}; } .button.primary:hover { opacity: 0.9; } `, ]; public render(): TemplateResult { return html`
Appearance
Customize the look and feel
Dark Mode Toggle dark mode on or off
this.toggleDarkMode()}>
Cloudflare Integration
Configure Cloudflare API for DNS management
API Token
this.updateSetting('cloudflareToken', (e.target as HTMLInputElement).value)}>
Zone ID (Optional)
this.updateSetting('cloudflareZoneId', (e.target as HTMLInputElement).value)}>
Get your API token from the Cloudflare dashboard with DNS edit permissions.
SSL/TLS Settings
Configure certificate management
Auto-Renew Certificates Automatically renew certificates before expiry
this.toggleSetting('autoRenewCerts')}>
Renewal Threshold (days)
this.updateSetting('renewalThreshold', parseInt((e.target as HTMLInputElement).value))}>
Renew certificates when they have fewer than this many days remaining.
ACME Email
this.updateSetting('acmeEmail', (e.target as HTMLInputElement).value)}>
Email address for Let's Encrypt notifications.
Network Settings
Configure network and proxy settings
HTTP Port
this.updateSetting('httpPort', parseInt((e.target as HTMLInputElement).value))}>
HTTPS Port
this.updateSetting('httpsPort', parseInt((e.target as HTMLInputElement).value))}>
Force HTTPS Redirect all HTTP traffic to HTTPS
this.toggleSetting('forceHttps')}>
Account
Manage your account settings
Current User
${this.currentUser || 'Unknown'}
Change Password
Current Password
New Password
Confirm Password
`; } private toggleDarkMode() { this.settings = { ...this.settings, darkMode: !this.settings.darkMode }; this.dispatchEvent(new CustomEvent('setting-change', { detail: { key: 'darkMode', value: this.settings.darkMode }, bubbles: true, composed: true })); } private toggleSetting(key: keyof ISettings) { (this.settings as any)[key] = !(this.settings as any)[key]; this.settings = { ...this.settings }; } private updateSetting(key: keyof ISettings, value: any) { (this.settings as any)[key] = value; this.settings = { ...this.settings }; } private handleChangePassword() { const currentPassword = (this.shadowRoot?.getElementById('currentPassword') as HTMLInputElement)?.value; const newPassword = (this.shadowRoot?.getElementById('newPassword') as HTMLInputElement)?.value; const confirmPassword = (this.shadowRoot?.getElementById('confirmPassword') as HTMLInputElement)?.value; this.dispatchEvent(new CustomEvent('change-password', { detail: { currentPassword, newPassword, confirmPassword }, bubbles: true, composed: true })); } private handleReset() { this.dispatchEvent(new CustomEvent('reset', { bubbles: true, composed: true })); } private handleSave() { this.dispatchEvent(new CustomEvent('save', { detail: this.settings, bubbles: true, composed: true })); } }