import * as plugins from '../../plugins.js'; import { DeesElement, property, html, customElement, type TemplateResult, css, cssManager, unsafeCSS, state, } from '@design.estate/dees-element'; import * as sharedStyles from '../../styles/shared.styles.js'; import type { IStatusPageConfig } from '../../interfaces/index.js'; import { demoFunc } from './upladmin-statuspage-config.demo.js'; declare global { interface HTMLElementTagNameMap { 'upladmin-statuspage-config': UpladminStatuspageConfig; } } @customElement('upladmin-statuspage-config') export class UpladminStatuspageConfig extends DeesElement { public static demo = demoFunc; @property({ type: Object }) accessor config: IStatusPageConfig = {}; @property({ type: Boolean }) accessor loading: boolean = false; @state() accessor formData: IStatusPageConfig = {}; @state() accessor activeSection: string = 'branding'; @state() accessor hasChanges: boolean = false; public static styles = [ plugins.domtools.elementBasic.staticStyles, sharedStyles.commonStyles, css` :host { display: block; font-family: ${unsafeCSS(sharedStyles.fonts.base)}; } .config-container { display: grid; grid-template-columns: 220px 1fr; gap: ${unsafeCSS(sharedStyles.spacing.lg)}; min-height: 500px; } @media (max-width: 768px) { .config-container { grid-template-columns: 1fr; } } .config-nav { background: ${sharedStyles.colors.background.secondary}; border: 1px solid ${sharedStyles.colors.border.default}; border-radius: ${unsafeCSS(sharedStyles.borderRadius.lg)}; padding: ${unsafeCSS(sharedStyles.spacing.sm)}; height: fit-content; } .nav-item { display: flex; align-items: center; gap: 12px; width: 100%; padding: 14px 16px; font-size: 14px; font-weight: 500; font-family: ${unsafeCSS(sharedStyles.fonts.base)}; color: ${sharedStyles.colors.text.secondary}; background: transparent; border: none; border-radius: ${unsafeCSS(sharedStyles.borderRadius.base)}; cursor: pointer; text-align: left; transition: all ${unsafeCSS(sharedStyles.durations.fast)} ${unsafeCSS(sharedStyles.easings.default)}; } .nav-item:hover { background: ${sharedStyles.colors.background.muted}; color: ${sharedStyles.colors.text.primary}; } .nav-item.active { background: ${sharedStyles.colors.accent.primary}; color: white; } .nav-item.active dees-icon { --icon-color: white; } .nav-item dees-icon { --icon-color: ${sharedStyles.colors.text.muted}; transition: color ${unsafeCSS(sharedStyles.durations.fast)} ${unsafeCSS(sharedStyles.easings.default)}; } .nav-item:hover dees-icon { --icon-color: ${sharedStyles.colors.text.primary}; } .config-content { background: ${sharedStyles.colors.background.secondary}; border: 1px solid ${sharedStyles.colors.border.default}; border-radius: ${unsafeCSS(sharedStyles.borderRadius.lg)}; overflow: hidden; } .content-header { display: flex; align-items: center; justify-content: space-between; padding: ${unsafeCSS(sharedStyles.spacing.md)} ${unsafeCSS(sharedStyles.spacing.lg)}; border-bottom: 1px solid ${sharedStyles.colors.border.default}; background: ${sharedStyles.colors.background.muted}; } .content-title { font-size: 16px; font-weight: 600; color: ${sharedStyles.colors.text.primary}; } .content-subtitle { font-size: 13px; color: ${sharedStyles.colors.text.muted}; margin-top: 2px; } .save-indicator { display: flex; align-items: center; gap: 8px; padding: 6px 12px; font-size: 12px; font-weight: 500; color: ${sharedStyles.colors.accent.warning}; background: ${cssManager.bdTheme('rgba(234, 179, 8, 0.1)', 'rgba(234, 179, 8, 0.15)')}; border-radius: ${unsafeCSS(sharedStyles.borderRadius.base)}; } .save-indicator dees-icon { --icon-color: ${sharedStyles.colors.accent.warning}; } .content-body { padding: ${unsafeCSS(sharedStyles.spacing.lg)}; } dees-form { display: contents; } .form-section { margin-bottom: ${unsafeCSS(sharedStyles.spacing.xl)}; } .form-section:last-child { margin-bottom: 0; } .section-title { display: flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 600; color: ${sharedStyles.colors.text.primary}; margin-bottom: ${unsafeCSS(sharedStyles.spacing.md)}; padding-bottom: ${unsafeCSS(sharedStyles.spacing.xs)}; border-bottom: 1px solid ${sharedStyles.colors.border.light}; } .section-title dees-icon { --icon-color: ${sharedStyles.colors.text.muted}; } .form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: ${unsafeCSS(sharedStyles.spacing.md)}; } .content-actions { display: flex; justify-content: flex-end; gap: ${unsafeCSS(sharedStyles.spacing.sm)}; padding: ${unsafeCSS(sharedStyles.spacing.md)} ${unsafeCSS(sharedStyles.spacing.lg)}; border-top: 1px solid ${sharedStyles.colors.border.default}; background: ${sharedStyles.colors.background.muted}; } .theme-options { display: flex; gap: ${unsafeCSS(sharedStyles.spacing.sm)}; } .theme-option { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 18px; background: ${sharedStyles.colors.background.primary}; border: 2px solid ${sharedStyles.colors.border.default}; border-radius: ${unsafeCSS(sharedStyles.borderRadius.base)}; cursor: pointer; transition: all ${unsafeCSS(sharedStyles.durations.fast)} ${unsafeCSS(sharedStyles.easings.default)}; } .theme-option:hover { border-color: ${sharedStyles.colors.border.strong}; } .theme-option.selected { border-color: ${sharedStyles.colors.accent.primary}; background: ${cssManager.bdTheme('rgba(59, 130, 246, 0.05)', 'rgba(96, 165, 250, 0.1)')}; } .theme-option input { display: none; } .theme-preview { width: 56px; height: 36px; border-radius: 6px; border: 1px solid ${sharedStyles.colors.border.default}; overflow: hidden; } .theme-preview.light { background: linear-gradient(180deg, #f8fafc 0%, #e2e8f0 100%); } .theme-preview.dark { background: linear-gradient(180deg, #1e293b 0%, #0f172a 100%); } .theme-preview.auto { background: linear-gradient(135deg, #f8fafc 0%, #f8fafc 50%, #1e293b 50%, #1e293b 100%); } .theme-label { font-size: 13px; font-weight: 500; color: ${sharedStyles.colors.text.primary}; } .logo-preview { display: flex; align-items: center; gap: ${unsafeCSS(sharedStyles.spacing.md)}; padding: ${unsafeCSS(sharedStyles.spacing.md)}; background: ${sharedStyles.colors.background.primary}; border: 1px solid ${sharedStyles.colors.border.default}; border-radius: ${unsafeCSS(sharedStyles.borderRadius.base)}; margin-top: ${unsafeCSS(sharedStyles.spacing.sm)}; } .logo-preview img { max-width: 140px; max-height: 48px; object-fit: contain; } .logo-placeholder { display: flex; align-items: center; gap: 8px; color: ${sharedStyles.colors.text.muted}; font-size: 13px; } .logo-placeholder dees-icon { --icon-color: ${sharedStyles.colors.text.muted}; opacity: 0.5; } .toggle-row { display: flex; align-items: center; gap: ${unsafeCSS(sharedStyles.spacing.md)}; padding: ${unsafeCSS(sharedStyles.spacing.sm)} 0; } .toggle-label { flex: 1; } .toggle-label-text { font-size: 14px; font-weight: 500; color: ${sharedStyles.colors.text.primary}; } .toggle-label-hint { font-size: 12px; color: ${sharedStyles.colors.text.muted}; margin-top: 2px; } /* Style dees-input components */ dees-input-text, dees-input-dropdown { --dees-input-background: ${sharedStyles.colors.background.primary}; --dees-input-border-color: ${sharedStyles.colors.border.default}; } ` ]; async connectedCallback() { await super.connectedCallback(); this.formData = { ...this.config }; } updated(changedProperties: Map) { if (changedProperties.has('config')) { this.formData = { ...this.config }; this.hasChanges = false; } } public render(): TemplateResult { const sections = [ { id: 'branding', icon: 'lucide:Palette', label: 'Branding', subtitle: 'Logo, company name, colors' }, { id: 'urls', icon: 'lucide:Link', label: 'URLs', subtitle: 'Links and endpoints' }, { id: 'behavior', icon: 'lucide:Settings', label: 'Behavior', subtitle: 'Refresh, notifications, history' }, { id: 'advanced', icon: 'lucide:Wrench', label: 'Advanced', subtitle: 'API, timezone, language' }, ]; return html`
${sections.find(s => s.id === this.activeSection)?.label}
${sections.find(s => s.id === this.activeSection)?.subtitle}
${this.hasChanges ? html`
Unsaved changes
` : ''}
${this.renderSection()}
Reset ${this.loading ? html`` : html``} Save Changes
`; } private renderSection(): TemplateResult { switch (this.activeSection) { case 'branding': return this.renderBrandingSection(); case 'urls': return this.renderUrlsSection(); case 'behavior': return this.renderBehaviorSection(); case 'advanced': return this.renderAdvancedSection(); default: return html``; } } private renderBrandingSection(): TemplateResult { const themeOptions: Array<{ value: 'light' | 'dark' | 'auto'; label: string; icon: string }> = [ { value: 'light', label: 'Light', icon: 'lucide:Sun' }, { value: 'dark', label: 'Dark', icon: 'lucide:Moon' }, { value: 'auto', label: 'Auto', icon: 'lucide:Monitor' }, ]; return html`
Company Information
${this.formData.companyLogo ? html`
Company logo
` : html`
No logo configured
`}
Theme
${themeOptions.map(opt => html` `)}
White Label Mode
Hide 'Powered by' branding
`; } private renderUrlsSection(): TemplateResult { return html`
Status Page URLs
API Configuration
`; } private renderBehaviorSection(): TemplateResult { return html`
Auto-refresh
History
Features
WebSocket Updates
Enable real-time updates
Browser Notifications
Allow push notifications
`; } private renderAdvancedSection(): TemplateResult { const timezoneOptions = [ { key: 'UTC', option: 'UTC', payload: null }, { key: 'America/New_York', option: 'Eastern Time (US)', payload: null }, { key: 'America/Los_Angeles', option: 'Pacific Time (US)', payload: null }, { key: 'Europe/London', option: 'London', payload: null }, { key: 'Europe/Berlin', option: 'Berlin', payload: null }, { key: 'Asia/Tokyo', option: 'Tokyo', payload: null }, { key: 'Asia/Shanghai', option: 'Shanghai', payload: null }, ]; const dateFormatOptions = [ { key: 'relative', option: 'Relative (2 hours ago)', payload: null }, { key: 'absolute', option: 'Absolute (Dec 23, 2024 14:30)', payload: null }, { key: 'iso', option: 'ISO (2024-12-23T14:30:00)', payload: null }, ]; const languageOptions = [ { key: 'en', option: 'English', payload: null }, { key: 'de', option: 'German', payload: null }, { key: 'fr', option: 'French', payload: null }, { key: 'es', option: 'Spanish', payload: null }, { key: 'ja', option: 'Japanese', payload: null }, { key: 'zh', option: 'Chinese', payload: null }, ]; return html`
Localization
`; } private handleTextChange(name: string, value: string) { this.formData = { ...this.formData, [name]: value }; this.hasChanges = true; } private handleNumberChange(name: string, value: string) { this.formData = { ...this.formData, [name]: parseInt(value, 10) || 0 }; this.hasChanges = true; } private handleBooleanChange(name: string, value: boolean) { this.formData = { ...this.formData, [name]: value }; this.hasChanges = true; } private handleDropdownChange(name: string, value: string) { this.formData = { ...this.formData, [name]: value }; this.hasChanges = true; } private handleThemeChange(theme: 'light' | 'dark' | 'auto') { this.formData = { ...this.formData, theme }; this.hasChanges = true; } private handleLogoError(e: Event) { const img = e.target as HTMLImageElement; img.style.display = 'none'; } private handleSave() { this.dispatchEvent(new CustomEvent('configSave', { detail: { config: { ...this.formData } }, bubbles: true, composed: true })); } private handleReset() { this.formData = { ...this.config }; this.hasChanges = false; } public setConfig(config: IStatusPageConfig) { this.formData = { ...config }; this.hasChanges = false; } }