import { DeesElement, property, html, customElement, type TemplateResult, css, cssManager, unsafeCSS } from '@design.estate/dees-element'; import * as domtools from '@design.estate/dees-domtools'; import * as sharedStyles from '../styles/shared.styles.js'; import { demoFunc } from './upl-statuspage-footer.demo.js'; declare global { interface HTMLElementTagNameMap { 'upl-statuspage-footer': UplStatuspageFooter; } } @customElement('upl-statuspage-footer') export class UplStatuspageFooter extends DeesElement { // STATIC public static demo = demoFunc; // INSTANCE @property({ type: String }) accessor companyName: string = ''; @property({ type: String }) accessor legalUrl: string = ''; @property({ type: String }) accessor supportEmail: string = ''; @property({ type: String }) accessor statusPageUrl: string = ''; @property({ type: Boolean }) accessor whitelabel: boolean = false; @property({ type: Number }) accessor lastUpdated: number | null = null; @property({ type: Number }) accessor currentYear: number = new Date().getFullYear(); @property({ type: Array }) accessor socialLinks: Array<{ platform: string; url: string }> = []; @property({ type: Array }) accessor additionalLinks: Array<{ label: string; url: string }> = []; @property({ type: String }) accessor rssFeedUrl: string = ''; @property({ type: String }) accessor apiStatusUrl: string = ''; @property({ type: Boolean }) accessor loading: boolean = false; @property({ type: String }) accessor errorMessage: string | null = null; @property({ type: Boolean }) accessor offline: boolean = false; @property({ type: String }) accessor latestStatusUpdate: string = ''; @property({ type: Boolean }) accessor enableSubscribe: boolean = false; @property({ type: Boolean }) accessor enableReportIssue: boolean = false; @property({ type: Boolean }) accessor enableLanguageSelector: boolean = false; @property({ type: Boolean }) accessor enableThemeToggle: boolean = false; @property({ type: Array }) accessor languageOptions: Array<{ code: string; label: string }> = []; @property({ type: String }) accessor currentLanguage: string = 'en'; @property({ type: String }) accessor currentTheme: string = 'light'; @property({ type: Number }) accessor subscriberCount: number = 0; @property({ type: Object }) accessor customBranding: { primaryColor?: string; logoUrl?: string; footerText?: string } | null = null; constructor() { super(); } public static styles = [ domtools.elementBasic.staticStyles, sharedStyles.commonStyles, css` :host { display: block; background: ${sharedStyles.colors.background.primary}; font-family: ${unsafeCSS(sharedStyles.fonts.base)}; color: ${sharedStyles.colors.text.primary}; font-size: 14px; border-top: 1px solid ${sharedStyles.colors.border.default}; } .container { max-width: 1200px; margin: 0 auto; padding: ${unsafeCSS(sharedStyles.spacing['2xl'])} ${unsafeCSS(sharedStyles.spacing.lg)}; } .footer-content { display: flex; flex-direction: column; gap: ${unsafeCSS(sharedStyles.spacing.xl)}; } .footer-main { display: flex; justify-content: space-between; align-items: start; gap: ${unsafeCSS(sharedStyles.spacing['2xl'])}; } .company-info { display: flex; flex-direction: column; gap: ${unsafeCSS(sharedStyles.spacing.lg)}; } .company-name { font-size: 16px; font-weight: 500; color: ${sharedStyles.colors.text.primary}; letter-spacing: -0.01em; } .company-links { display: flex; flex-wrap: wrap; gap: ${unsafeCSS(sharedStyles.spacing.lg)}; } .footer-link { color: ${cssManager.bdTheme('#6b7280', '#a1a1aa')}; text-decoration: none; transition: color 0.15s ease; font-size: 13px; font-weight: 400; } .footer-link:hover { color: ${sharedStyles.colors.text.primary}; } .footer-actions { display: flex; flex-direction: column; gap: ${unsafeCSS(sharedStyles.spacing.md)}; } .action-button { padding: 8px 16px; height: 36px; border: 1px solid ${cssManager.bdTheme('#e5e7eb', '#27272a')}; background: ${cssManager.bdTheme('#ffffff', '#0a0a0a')}; border-radius: 6px; cursor: pointer; text-align: center; transition: all 0.15s ease; white-space: nowrap; font-size: 13px; font-weight: 400; color: ${sharedStyles.colors.text.primary}; font-family: ${unsafeCSS(sharedStyles.fonts.base)}; display: inline-flex; align-items: center; justify-content: center; } .action-button:hover { background: ${cssManager.bdTheme('#f9fafb', '#18181b')}; border-color: ${cssManager.bdTheme('#d1d5db', '#3f3f46')}; } .footer-bottom { display: flex; justify-content: space-between; align-items: center; padding-top: ${unsafeCSS(sharedStyles.spacing.lg)}; margin-top: ${unsafeCSS(sharedStyles.spacing.lg)}; border-top: 1px solid ${cssManager.bdTheme('#e5e7eb', '#27272a')}; } .footer-meta { display: flex; gap: ${unsafeCSS(sharedStyles.spacing.lg)}; align-items: center; flex-wrap: wrap; } .social-links { display: flex; gap: ${unsafeCSS(sharedStyles.spacing.md)}; align-items: center; } .social-link { display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border-radius: 6px; transition: all 0.15s ease; color: ${cssManager.bdTheme('#6b7280', '#a1a1aa')}; } .social-link:hover { color: ${sharedStyles.colors.text.primary}; background: ${cssManager.bdTheme('#f3f4f6', '#27272a')}; } .social-link svg { width: 16px; height: 16px; fill: currentColor; } .copyright { font-size: 13px; color: ${cssManager.bdTheme('#6b7280', '#a1a1aa')}; } .last-updated { font-size: 12px; color: ${cssManager.bdTheme('#9ca3af', '#71717a')}; } .powered-by { font-size: 12px; color: ${cssManager.bdTheme('#9ca3af', '#71717a')}; text-align: right; } .powered-by a { color: ${cssManager.bdTheme('#6b7280', '#a1a1aa')}; text-decoration: none; transition: color 0.15s ease; } .powered-by a:hover { color: ${sharedStyles.colors.text.primary}; } .status-update { padding: 12px 16px; background: ${cssManager.bdTheme('#f9fafb', '#18181b')}; border: 1px solid ${cssManager.bdTheme('#e5e7eb', '#27272a')}; border-radius: 6px; font-size: 13px; margin-bottom: ${unsafeCSS(sharedStyles.spacing.lg)}; line-height: 1.5; color: ${cssManager.bdTheme('#4b5563', '#d1d5db')}; } .language-selector { position: relative; } .language-selector select { padding: ${unsafeCSS(sharedStyles.spacing.xs)} ${unsafeCSS(sharedStyles.spacing.sm)}; border: 1px solid ${sharedStyles.colors.border.default}; background: ${sharedStyles.colors.background.primary}; color: ${sharedStyles.colors.text.primary}; border-radius: ${unsafeCSS(sharedStyles.borderRadius.base)}; font-size: 14px; cursor: pointer; font-family: ${unsafeCSS(sharedStyles.fonts.base)}; } .theme-toggle { cursor: pointer; padding: ${unsafeCSS(sharedStyles.spacing.xs)} ${unsafeCSS(sharedStyles.spacing.sm)}; border: 1px solid ${sharedStyles.colors.border.default}; background: transparent; border-radius: ${unsafeCSS(sharedStyles.borderRadius.base)}; font-size: 14px; transition: all 0.2s ease; color: ${sharedStyles.colors.text.primary}; font-family: ${unsafeCSS(sharedStyles.fonts.base)}; } .theme-toggle:hover { background: ${sharedStyles.colors.background.secondary}; border-color: ${sharedStyles.colors.border.muted}; } .subscribe-wrapper { display: flex; flex-direction: column; align-items: center; gap: ${unsafeCSS(sharedStyles.spacing.xs)}; } .subscriber-count { font-size: 12px; color: ${cssManager.bdTheme('#6b7280', '#a1a1aa')}; } .error-message { padding: ${unsafeCSS(sharedStyles.spacing.md)}; background: ${cssManager.bdTheme('#fee9e9', '#7f1d1d')}; color: ${cssManager.bdTheme('#dc2626', '#fca5a5')}; border-radius: ${unsafeCSS(sharedStyles.borderRadius.base)}; margin-bottom: ${unsafeCSS(sharedStyles.spacing.lg)}; font-size: 14px; border: 1px solid ${cssManager.bdTheme('#fecaca', '#991b1b')}; } .offline-indicator { display: inline-flex; align-items: center; gap: ${unsafeCSS(sharedStyles.spacing.xs)}; padding: ${unsafeCSS(sharedStyles.spacing.xs)} ${unsafeCSS(sharedStyles.spacing.md)}; background: ${sharedStyles.colors.status.degraded}; color: white; border-radius: ${unsafeCSS(sharedStyles.borderRadius.full)}; font-size: 13px; font-weight: 500; } .loading-skeleton { height: 200px; background: ${cssManager.bdTheme( 'linear-gradient(90deg, #f3f4f6 25%, #e5e7eb 50%, #f3f4f6 75%)', 'linear-gradient(90deg, #1f1f1f 25%, #262626 50%, #1f1f1f 75%)' )}; background-size: 200% 100%; animation: loading 1.5s infinite; border-radius: ${unsafeCSS(sharedStyles.borderRadius.md)}; } @keyframes loading { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } } .additional-links { display: flex; flex-wrap: wrap; gap: ${unsafeCSS(sharedStyles.spacing.md)}; margin-top: ${unsafeCSS(sharedStyles.spacing.md)}; } .additional-link { font-size: 13px; color: ${cssManager.bdTheme('#6b7280', '#a1a1aa')}; text-decoration: none; transition: color 0.15s ease; } .additional-link:hover { color: ${sharedStyles.colors.text.primary}; } @media (max-width: 640px) { .container { padding: ${unsafeCSS(sharedStyles.spacing.lg)} ${unsafeCSS(sharedStyles.spacing.md)}; } .footer-main { flex-direction: column; gap: ${unsafeCSS(sharedStyles.spacing.lg)}; } .footer-bottom { flex-direction: column; gap: ${unsafeCSS(sharedStyles.spacing.lg)}; align-items: start; } .footer-meta { flex-direction: column; align-items: start; gap: ${unsafeCSS(sharedStyles.spacing.md)}; } .company-links { flex-direction: column; gap: ${unsafeCSS(sharedStyles.spacing.sm)}; } .powered-by { text-align: left; } } ` ] public render(): TemplateResult { if (this.loading) { return html`