initial
This commit is contained in:
1
ts_web/elements/upladmin-statuspage-config/index.ts
Normal file
1
ts_web/elements/upladmin-statuspage-config/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './upladmin-statuspage-config.js';
|
||||
@@ -0,0 +1,47 @@
|
||||
import { html, css, cssManager } from '@design.estate/dees-element';
|
||||
import type { IStatusPageConfig } from '../../interfaces/index.js';
|
||||
import './upladmin-statuspage-config.js';
|
||||
|
||||
export const demoFunc = () => html`
|
||||
<style>
|
||||
${css`
|
||||
.demo-container {
|
||||
padding: 24px;
|
||||
background: ${cssManager.bdTheme('#fafafa', '#0a0a0a')};
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.demo-title {
|
||||
margin: 0 0 24px 0;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: ${cssManager.bdTheme('#71717a', '#a1a1aa')};
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
|
||||
<div class="demo-container">
|
||||
<h3 class="demo-title">Status Page Configuration</h3>
|
||||
<upladmin-statuspage-config
|
||||
.config=${{
|
||||
companyName: 'Acme Corporation',
|
||||
companyLogo: 'https://via.placeholder.com/200x60?text=ACME',
|
||||
supportEmail: 'support@acme.example.com',
|
||||
statusPageUrl: 'https://status.acme.example.com',
|
||||
legalUrl: 'https://acme.example.com/terms',
|
||||
apiEndpoint: 'https://api.acme.example.com/status',
|
||||
theme: 'auto',
|
||||
whitelabel: false,
|
||||
refreshInterval: 60,
|
||||
showHistoricalDays: 90,
|
||||
enableWebSocket: true,
|
||||
enableNotifications: false,
|
||||
timeZone: 'America/New_York',
|
||||
language: 'en',
|
||||
dateFormat: 'relative',
|
||||
} as IStatusPageConfig}
|
||||
></upladmin-statuspage-config>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,717 @@
|
||||
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<string, unknown>) {
|
||||
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`
|
||||
<div class="config-container">
|
||||
<nav class="config-nav">
|
||||
${sections.map(section => html`
|
||||
<button
|
||||
class="nav-item ${this.activeSection === section.id ? 'active' : ''}"
|
||||
@click="${() => this.activeSection = section.id}"
|
||||
>
|
||||
<dees-icon .icon=${section.icon} .iconSize=${18}></dees-icon>
|
||||
<span>${section.label}</span>
|
||||
</button>
|
||||
`)}
|
||||
</nav>
|
||||
|
||||
<div class="config-content">
|
||||
<div class="content-header">
|
||||
<div>
|
||||
<div class="content-title">${sections.find(s => s.id === this.activeSection)?.label}</div>
|
||||
<div class="content-subtitle">${sections.find(s => s.id === this.activeSection)?.subtitle}</div>
|
||||
</div>
|
||||
${this.hasChanges ? html`
|
||||
<div class="save-indicator">
|
||||
<dees-icon .icon=${'lucide:AlertCircle'} .iconSize=${14}></dees-icon>
|
||||
<span>Unsaved changes</span>
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
|
||||
<div class="content-body">
|
||||
<dees-form>
|
||||
${this.renderSection()}
|
||||
</dees-form>
|
||||
</div>
|
||||
|
||||
<div class="content-actions">
|
||||
<dees-button type="discreet" @click="${this.handleReset}" ?disabled="${!this.hasChanges || this.loading}">
|
||||
<dees-icon .icon=${'lucide:RotateCcw'} .iconSize=${14}></dees-icon>
|
||||
Reset
|
||||
</dees-button>
|
||||
<dees-button type="highlighted" @click="${this.handleSave}" ?disabled="${!this.hasChanges || this.loading}">
|
||||
${this.loading ? html`<dees-spinner .size=${16}></dees-spinner>` : html`<dees-icon .icon=${'lucide:Save'} .iconSize=${16}></dees-icon>`}
|
||||
Save Changes
|
||||
</dees-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
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`
|
||||
<div class="form-section">
|
||||
<div class="section-title">
|
||||
<dees-icon .icon=${'lucide:Building'} .iconSize=${16}></dees-icon>
|
||||
Company Information
|
||||
</div>
|
||||
<div class="form-grid">
|
||||
<dees-input-text
|
||||
key="companyName"
|
||||
label="Company Name"
|
||||
.value="${this.formData.companyName || ''}"
|
||||
placeholder="Your Company"
|
||||
description="Displayed in the header and footer"
|
||||
@changeSubject="${(e: CustomEvent) => this.handleTextChange('companyName', e.detail)}"
|
||||
></dees-input-text>
|
||||
|
||||
<dees-input-text
|
||||
key="supportEmail"
|
||||
label="Support Email"
|
||||
.value="${this.formData.supportEmail || ''}"
|
||||
placeholder="support@example.com"
|
||||
description="Contact email for users"
|
||||
@changeSubject="${(e: CustomEvent) => this.handleTextChange('supportEmail', e.detail)}"
|
||||
></dees-input-text>
|
||||
</div>
|
||||
|
||||
<dees-input-text
|
||||
key="companyLogo"
|
||||
label="Company Logo URL"
|
||||
.value="${this.formData.companyLogo || ''}"
|
||||
placeholder="https://example.com/logo.png"
|
||||
@changeSubject="${(e: CustomEvent) => this.handleTextChange('companyLogo', e.detail)}"
|
||||
></dees-input-text>
|
||||
|
||||
${this.formData.companyLogo ? html`
|
||||
<div class="logo-preview">
|
||||
<img src="${this.formData.companyLogo}" alt="Company logo" @error="${this.handleLogoError}" />
|
||||
</div>
|
||||
` : html`
|
||||
<div class="logo-preview">
|
||||
<div class="logo-placeholder">
|
||||
<dees-icon .icon=${'lucide:Image'} .iconSize=${20}></dees-icon>
|
||||
No logo configured
|
||||
</div>
|
||||
</div>
|
||||
`}
|
||||
</div>
|
||||
|
||||
<div class="form-section">
|
||||
<div class="section-title">
|
||||
<dees-icon .icon=${'lucide:Palette'} .iconSize=${16}></dees-icon>
|
||||
Theme
|
||||
</div>
|
||||
<div class="theme-options">
|
||||
${themeOptions.map(opt => html`
|
||||
<label
|
||||
class="theme-option ${this.formData.theme === opt.value ? 'selected' : ''}"
|
||||
@click="${() => this.handleThemeChange(opt.value)}"
|
||||
>
|
||||
<input type="radio" name="theme" value="${opt.value}" ?checked="${this.formData.theme === opt.value}" />
|
||||
<div class="theme-preview ${opt.value}"></div>
|
||||
<span class="theme-label">${opt.label}</span>
|
||||
</label>
|
||||
`)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-section">
|
||||
<div class="toggle-row">
|
||||
<div class="toggle-label">
|
||||
<div class="toggle-label-text">White Label Mode</div>
|
||||
<div class="toggle-label-hint">Hide 'Powered by' branding</div>
|
||||
</div>
|
||||
<dees-input-checkbox
|
||||
key="whitelabel"
|
||||
.value="${this.formData.whitelabel || false}"
|
||||
@changeSubject="${(e: CustomEvent) => this.handleBooleanChange('whitelabel', e.detail)}"
|
||||
></dees-input-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private renderUrlsSection(): TemplateResult {
|
||||
return html`
|
||||
<div class="form-section">
|
||||
<div class="section-title">
|
||||
<dees-icon .icon=${'lucide:Globe'} .iconSize=${16}></dees-icon>
|
||||
Status Page URLs
|
||||
</div>
|
||||
<div class="form-grid">
|
||||
<dees-input-text
|
||||
key="statusPageUrl"
|
||||
label="Status Page URL"
|
||||
.value="${this.formData.statusPageUrl || ''}"
|
||||
placeholder="https://status.example.com"
|
||||
description="Public URL of your status page"
|
||||
@changeSubject="${(e: CustomEvent) => this.handleTextChange('statusPageUrl', e.detail)}"
|
||||
></dees-input-text>
|
||||
|
||||
<dees-input-text
|
||||
key="legalUrl"
|
||||
label="Legal / Terms URL"
|
||||
.value="${this.formData.legalUrl || ''}"
|
||||
placeholder="https://example.com/terms"
|
||||
description="Link to terms of service or legal info"
|
||||
@changeSubject="${(e: CustomEvent) => this.handleTextChange('legalUrl', e.detail)}"
|
||||
></dees-input-text>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-section">
|
||||
<div class="section-title">
|
||||
<dees-icon .icon=${'lucide:Server'} .iconSize=${16}></dees-icon>
|
||||
API Configuration
|
||||
</div>
|
||||
<dees-input-text
|
||||
key="apiEndpoint"
|
||||
label="API Endpoint"
|
||||
.value="${this.formData.apiEndpoint || ''}"
|
||||
placeholder="https://api.example.com/status"
|
||||
description="Base URL for status API requests"
|
||||
@changeSubject="${(e: CustomEvent) => this.handleTextChange('apiEndpoint', e.detail)}"
|
||||
></dees-input-text>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private renderBehaviorSection(): TemplateResult {
|
||||
return html`
|
||||
<div class="form-section">
|
||||
<div class="section-title">
|
||||
<dees-icon .icon=${'lucide:RefreshCw'} .iconSize=${16}></dees-icon>
|
||||
Auto-refresh
|
||||
</div>
|
||||
<dees-input-text
|
||||
key="refreshInterval"
|
||||
label="Refresh Interval (seconds)"
|
||||
inputType="number"
|
||||
.value="${String(this.formData.refreshInterval || 60)}"
|
||||
placeholder="60"
|
||||
description="How often to refresh status data (minimum 30 seconds)"
|
||||
@changeSubject="${(e: CustomEvent) => this.handleNumberChange('refreshInterval', e.detail)}"
|
||||
></dees-input-text>
|
||||
</div>
|
||||
|
||||
<div class="form-section">
|
||||
<div class="section-title">
|
||||
<dees-icon .icon=${'lucide:History'} .iconSize=${16}></dees-icon>
|
||||
History
|
||||
</div>
|
||||
<dees-input-text
|
||||
key="showHistoricalDays"
|
||||
label="Historical Days to Show"
|
||||
inputType="number"
|
||||
.value="${String(this.formData.showHistoricalDays || 90)}"
|
||||
placeholder="90"
|
||||
description="Number of days of history to display"
|
||||
@changeSubject="${(e: CustomEvent) => this.handleNumberChange('showHistoricalDays', e.detail)}"
|
||||
></dees-input-text>
|
||||
</div>
|
||||
|
||||
<div class="form-section">
|
||||
<div class="section-title">
|
||||
<dees-icon .icon=${'lucide:Zap'} .iconSize=${16}></dees-icon>
|
||||
Features
|
||||
</div>
|
||||
<div class="toggle-row">
|
||||
<div class="toggle-label">
|
||||
<div class="toggle-label-text">WebSocket Updates</div>
|
||||
<div class="toggle-label-hint">Enable real-time updates</div>
|
||||
</div>
|
||||
<dees-input-checkbox
|
||||
key="enableWebSocket"
|
||||
.value="${this.formData.enableWebSocket || false}"
|
||||
@changeSubject="${(e: CustomEvent) => this.handleBooleanChange('enableWebSocket', e.detail)}"
|
||||
></dees-input-checkbox>
|
||||
</div>
|
||||
|
||||
<div class="toggle-row">
|
||||
<div class="toggle-label">
|
||||
<div class="toggle-label-text">Browser Notifications</div>
|
||||
<div class="toggle-label-hint">Allow push notifications</div>
|
||||
</div>
|
||||
<dees-input-checkbox
|
||||
key="enableNotifications"
|
||||
.value="${this.formData.enableNotifications || false}"
|
||||
@changeSubject="${(e: CustomEvent) => this.handleBooleanChange('enableNotifications', e.detail)}"
|
||||
></dees-input-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
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`
|
||||
<div class="form-section">
|
||||
<div class="section-title">
|
||||
<dees-icon .icon=${'lucide:Globe2'} .iconSize=${16}></dees-icon>
|
||||
Localization
|
||||
</div>
|
||||
<div class="form-grid">
|
||||
<dees-input-dropdown
|
||||
key="timeZone"
|
||||
label="Timezone"
|
||||
.options="${timezoneOptions}"
|
||||
.selectedOption="${this.formData.timeZone || 'UTC'}"
|
||||
@selectedOption="${(e: CustomEvent) => this.handleDropdownChange('timeZone', e.detail)}"
|
||||
></dees-input-dropdown>
|
||||
|
||||
<dees-input-dropdown
|
||||
key="language"
|
||||
label="Language"
|
||||
.options="${languageOptions}"
|
||||
.selectedOption="${this.formData.language || 'en'}"
|
||||
@selectedOption="${(e: CustomEvent) => this.handleDropdownChange('language', e.detail)}"
|
||||
></dees-input-dropdown>
|
||||
|
||||
<dees-input-dropdown
|
||||
key="dateFormat"
|
||||
label="Date Format"
|
||||
.options="${dateFormatOptions}"
|
||||
.selectedOption="${this.formData.dateFormat || 'relative'}"
|
||||
@selectedOption="${(e: CustomEvent) => this.handleDropdownChange('dateFormat', e.detail)}"
|
||||
></dees-input-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user