@uptime.link/statuspage 1.0.73 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/dist_bundle/bundle.js +4096 -504
  2. package/dist_bundle/bundle.js.map +4 -4
  3. package/dist_ts_web/00_commitinfo_data.js +2 -2
  4. package/dist_ts_web/elements/index.d.ts +3 -0
  5. package/dist_ts_web/elements/index.js +6 -1
  6. package/dist_ts_web/elements/internal/uplinternal-miniheading.d.ts +1 -0
  7. package/dist_ts_web/elements/internal/uplinternal-miniheading.js +78 -28
  8. package/dist_ts_web/elements/upl-statuspage-assetsselector.d.ts +14 -0
  9. package/dist_ts_web/elements/upl-statuspage-assetsselector.demo.d.ts +1 -0
  10. package/dist_ts_web/elements/upl-statuspage-assetsselector.demo.js +575 -0
  11. package/dist_ts_web/elements/upl-statuspage-assetsselector.js +605 -43
  12. package/dist_ts_web/elements/upl-statuspage-footer.d.ts +46 -2
  13. package/dist_ts_web/elements/upl-statuspage-footer.demo.d.ts +1 -0
  14. package/dist_ts_web/elements/upl-statuspage-footer.demo.js +679 -0
  15. package/dist_ts_web/elements/upl-statuspage-footer.js +792 -61
  16. package/dist_ts_web/elements/upl-statuspage-header.d.ts +5 -1
  17. package/dist_ts_web/elements/upl-statuspage-header.demo.d.ts +1 -0
  18. package/dist_ts_web/elements/upl-statuspage-header.demo.js +220 -0
  19. package/dist_ts_web/elements/upl-statuspage-header.js +313 -86
  20. package/dist_ts_web/elements/upl-statuspage-incidents.d.ts +22 -4
  21. package/dist_ts_web/elements/upl-statuspage-incidents.demo.d.ts +1 -0
  22. package/dist_ts_web/elements/upl-statuspage-incidents.demo.js +1147 -0
  23. package/dist_ts_web/elements/upl-statuspage-incidents.js +750 -74
  24. package/dist_ts_web/elements/upl-statuspage-pagetitle.d.ts +15 -0
  25. package/dist_ts_web/elements/upl-statuspage-pagetitle.demo.d.ts +1 -0
  26. package/dist_ts_web/elements/upl-statuspage-pagetitle.demo.js +25 -0
  27. package/dist_ts_web/elements/upl-statuspage-pagetitle.js +148 -0
  28. package/dist_ts_web/elements/upl-statuspage-statsgrid.d.ts +23 -0
  29. package/dist_ts_web/elements/upl-statuspage-statsgrid.demo.d.ts +1 -0
  30. package/dist_ts_web/elements/upl-statuspage-statsgrid.demo.js +295 -0
  31. package/dist_ts_web/elements/upl-statuspage-statsgrid.js +374 -0
  32. package/dist_ts_web/elements/upl-statuspage-statusbar.d.ts +4 -0
  33. package/dist_ts_web/elements/upl-statuspage-statusbar.demo.d.ts +1 -0
  34. package/dist_ts_web/elements/upl-statuspage-statusbar.demo.js +365 -0
  35. package/dist_ts_web/elements/upl-statuspage-statusbar.js +357 -44
  36. package/dist_ts_web/elements/upl-statuspage-statusdetails.d.ts +14 -0
  37. package/dist_ts_web/elements/upl-statuspage-statusdetails.demo.d.ts +1 -0
  38. package/dist_ts_web/elements/upl-statuspage-statusdetails.demo.js +706 -0
  39. package/dist_ts_web/elements/upl-statuspage-statusdetails.js +373 -63
  40. package/dist_ts_web/elements/upl-statuspage-statusmonth.d.ts +15 -0
  41. package/dist_ts_web/elements/upl-statuspage-statusmonth.demo.d.ts +1 -0
  42. package/dist_ts_web/elements/upl-statuspage-statusmonth.demo.js +798 -0
  43. package/dist_ts_web/elements/upl-statuspage-statusmonth.js +474 -100
  44. package/dist_ts_web/interfaces/index.d.ts +84 -0
  45. package/dist_ts_web/interfaces/index.js +4 -0
  46. package/dist_ts_web/pages/index.d.ts +4 -1
  47. package/dist_ts_web/pages/index.js +5 -2
  48. package/dist_ts_web/pages/statuspage-allgreen.d.ts +1 -0
  49. package/dist_ts_web/pages/statuspage-allgreen.js +386 -0
  50. package/dist_ts_web/pages/statuspage-demo.d.ts +1 -0
  51. package/dist_ts_web/pages/statuspage-demo.js +616 -0
  52. package/dist_ts_web/pages/statuspage-maintenance.d.ts +1 -0
  53. package/dist_ts_web/pages/statuspage-maintenance.js +544 -0
  54. package/dist_ts_web/pages/statuspage-outage.d.ts +1 -0
  55. package/dist_ts_web/pages/statuspage-outage.js +543 -0
  56. package/dist_ts_web/styles/shared.styles.d.ts +80 -0
  57. package/dist_ts_web/styles/shared.styles.js +351 -0
  58. package/dist_watch/bundle.js +54534 -26433
  59. package/dist_watch/bundle.js.map +4 -4
  60. package/dist_watch/index.html +3 -10
  61. package/npmextra.json +9 -3
  62. package/package.json +19 -19
  63. package/readme.hints.md +292 -0
  64. package/readme.md +326 -149
  65. package/readme.plan.md +261 -0
  66. package/ts_web/00_commitinfo_data.ts +1 -1
  67. package/ts_web/elements/index.ts +6 -0
  68. package/ts_web/elements/internal/uplinternal-miniheading.ts +24 -17
  69. package/ts_web/elements/upl-statuspage-assetsselector.demo.ts +607 -0
  70. package/ts_web/elements/upl-statuspage-assetsselector.ts +526 -18
  71. package/ts_web/elements/upl-statuspage-footer.demo.ts +744 -0
  72. package/ts_web/elements/upl-statuspage-footer.ts +608 -30
  73. package/ts_web/elements/upl-statuspage-header.demo.ts +241 -0
  74. package/ts_web/elements/upl-statuspage-header.ts +220 -52
  75. package/ts_web/elements/upl-statuspage-incidents.demo.ts +1216 -0
  76. package/ts_web/elements/upl-statuspage-incidents.ts +649 -26
  77. package/ts_web/elements/upl-statuspage-pagetitle.demo.ts +25 -0
  78. package/ts_web/elements/upl-statuspage-pagetitle.ts +89 -0
  79. package/ts_web/elements/upl-statuspage-statsgrid.demo.ts +315 -0
  80. package/ts_web/elements/upl-statuspage-statsgrid.ts +306 -0
  81. package/ts_web/elements/upl-statuspage-statusbar.demo.ts +393 -0
  82. package/ts_web/elements/upl-statuspage-statusbar.ts +281 -20
  83. package/ts_web/elements/upl-statuspage-statusdetails.demo.ts +754 -0
  84. package/ts_web/elements/upl-statuspage-statusdetails.ts +297 -38
  85. package/ts_web/elements/upl-statuspage-statusmonth.demo.ts +876 -0
  86. package/ts_web/elements/upl-statuspage-statusmonth.ts +397 -76
  87. package/ts_web/interfaces/index.ts +95 -0
  88. package/ts_web/pages/index.ts +4 -1
  89. package/ts_web/pages/statuspage-allgreen.ts +412 -0
  90. package/ts_web/pages/statuspage-demo.ts +653 -0
  91. package/ts_web/pages/statuspage-maintenance.ts +570 -0
  92. package/ts_web/pages/statuspage-outage.ts +568 -0
  93. package/ts_web/styles/shared.styles.ts +367 -0
  94. package/dist_ts_web/pages/page1.d.ts +0 -1
  95. package/dist_ts_web/pages/page1.js +0 -11
  96. package/ts_web/pages/page1.ts +0 -11
@@ -0,0 +1,744 @@
1
+ import { html } from '@design.estate/dees-element';
2
+ import type { IStatusPageConfig } from '../interfaces/index.js';
3
+
4
+ export const demoFunc = () => html`
5
+ <style>
6
+ .demo-container {
7
+ display: flex;
8
+ flex-direction: column;
9
+ gap: 20px;
10
+ }
11
+ .demo-section {
12
+ border: 1px solid #ddd;
13
+ border-radius: 8px;
14
+ padding: 20px;
15
+ background: #f5f5f5;
16
+ }
17
+ .demo-title {
18
+ font-size: 14px;
19
+ font-weight: 600;
20
+ margin-bottom: 16px;
21
+ color: #333;
22
+ }
23
+ .demo-controls {
24
+ display: flex;
25
+ gap: 10px;
26
+ margin-top: 16px;
27
+ flex-wrap: wrap;
28
+ }
29
+ .demo-button {
30
+ padding: 6px 12px;
31
+ border: 1px solid #ddd;
32
+ background: white;
33
+ border-radius: 4px;
34
+ cursor: pointer;
35
+ font-size: 13px;
36
+ }
37
+ .demo-button:hover {
38
+ background: #f0f0f0;
39
+ }
40
+ .demo-button.active {
41
+ background: #2196F3;
42
+ color: white;
43
+ border-color: #2196F3;
44
+ }
45
+ .demo-info {
46
+ margin-top: 12px;
47
+ padding: 12px;
48
+ background: white;
49
+ border-radius: 4px;
50
+ font-size: 13px;
51
+ line-height: 1.6;
52
+ }
53
+ .event-log {
54
+ margin-top: 12px;
55
+ padding: 12px;
56
+ background: #f9f9f9;
57
+ border-radius: 4px;
58
+ font-size: 12px;
59
+ max-height: 150px;
60
+ overflow-y: auto;
61
+ font-family: monospace;
62
+ }
63
+ .config-display {
64
+ display: grid;
65
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
66
+ gap: 12px;
67
+ margin-top: 12px;
68
+ }
69
+ .config-item {
70
+ background: white;
71
+ padding: 12px;
72
+ border-radius: 4px;
73
+ font-size: 12px;
74
+ }
75
+ .config-label {
76
+ font-weight: 600;
77
+ color: #666;
78
+ margin-bottom: 4px;
79
+ }
80
+ .config-value {
81
+ word-break: break-word;
82
+ }
83
+ </style>
84
+
85
+ <div class="demo-container">
86
+ <!-- Different Configuration Scenarios -->
87
+ <div class="demo-section">
88
+ <div class="demo-title">Different Footer Configurations</div>
89
+ <dees-demowrapper
90
+ .runAfterRender=${async (wrapperElement: any) => {
91
+ const footer = wrapperElement.querySelector('upl-statuspage-footer') as any;
92
+
93
+ // Configuration presets
94
+ const configPresets = {
95
+ minimal: {
96
+ name: 'Minimal',
97
+ config: {
98
+ companyName: 'SimpleStatus',
99
+ whitelabel: true,
100
+ lastUpdated: Date.now()
101
+ }
102
+ },
103
+ standard: {
104
+ name: 'Standard',
105
+ config: {
106
+ companyName: 'TechCorp Solutions',
107
+ legalUrl: 'https://example.com/legal',
108
+ supportEmail: 'support@techcorp.com',
109
+ statusPageUrl: 'https://status.techcorp.com',
110
+ whitelabel: false,
111
+ lastUpdated: Date.now(),
112
+ currentYear: new Date().getFullYear()
113
+ }
114
+ },
115
+ fullFeatured: {
116
+ name: 'Full Featured',
117
+ config: {
118
+ companyName: 'Enterprise Cloud Platform',
119
+ legalUrl: 'https://enterprise.com/legal',
120
+ supportEmail: 'support@enterprise.com',
121
+ statusPageUrl: 'https://status.enterprise.com',
122
+ whitelabel: false,
123
+ socialLinks: [
124
+ { platform: 'twitter', url: 'https://twitter.com/enterprise' },
125
+ { platform: 'github', url: 'https://github.com/enterprise' },
126
+ { platform: 'linkedin', url: 'https://linkedin.com/company/enterprise' },
127
+ { platform: 'facebook', url: 'https://facebook.com/enterprise' },
128
+ { platform: 'youtube', url: 'https://youtube.com/enterprise' }
129
+ ],
130
+ rssFeedUrl: 'https://status.enterprise.com/rss',
131
+ apiStatusUrl: 'https://api.enterprise.com/v1/status',
132
+ lastUpdated: Date.now(),
133
+ currentYear: new Date().getFullYear(),
134
+ language: 'en',
135
+ additionalLinks: [
136
+ { label: 'API Docs', url: 'https://docs.enterprise.com' },
137
+ { label: 'Service SLA', url: 'https://enterprise.com/sla' },
138
+ { label: 'Security', url: 'https://enterprise.com/security' }
139
+ ]
140
+ }
141
+ },
142
+ international: {
143
+ name: 'International',
144
+ config: {
145
+ companyName: 'Global Services GmbH',
146
+ legalUrl: 'https://global.eu/legal',
147
+ supportEmail: 'support@global.eu',
148
+ statusPageUrl: 'https://status.global.eu',
149
+ whitelabel: false,
150
+ language: 'de',
151
+ currentYear: new Date().getFullYear(),
152
+ lastUpdated: Date.now(),
153
+ languageOptions: [
154
+ { code: 'en', label: 'English' },
155
+ { code: 'de', label: 'Deutsch' },
156
+ { code: 'fr', label: 'Français' },
157
+ { code: 'es', label: 'Español' },
158
+ { code: 'ja', label: '日本語' }
159
+ ],
160
+ socialLinks: [
161
+ { platform: 'twitter', url: 'https://twitter.com/global_eu' },
162
+ { platform: 'linkedin', url: 'https://linkedin.com/company/global-eu' }
163
+ ]
164
+ }
165
+ },
166
+ whitelabel: {
167
+ name: 'Whitelabel',
168
+ config: {
169
+ companyName: 'Custom Brand Status',
170
+ whitelabel: true,
171
+ customBranding: {
172
+ primaryColor: '#FF5722',
173
+ logoUrl: 'https://example.com/custom-logo.png',
174
+ footerText: 'Powered by Custom Infrastructure'
175
+ },
176
+ lastUpdated: Date.now(),
177
+ currentYear: new Date().getFullYear()
178
+ }
179
+ }
180
+ };
181
+
182
+ // Initial setup
183
+ let currentPreset = 'standard';
184
+ const applyPreset = (preset: any) => {
185
+ Object.keys(preset.config).forEach(key => {
186
+ footer[key] = preset.config[key];
187
+ });
188
+ updateConfigDisplay(preset.config);
189
+ };
190
+
191
+ applyPreset(configPresets[currentPreset]);
192
+
193
+ // Create controls
194
+ const controls = document.createElement('div');
195
+ controls.className = 'demo-controls';
196
+
197
+ Object.entries(configPresets).forEach(([key, preset]) => {
198
+ const button = document.createElement('button');
199
+ button.className = 'demo-button' + (key === currentPreset ? ' active' : '');
200
+ button.textContent = preset.name;
201
+ button.onclick = () => {
202
+ controls.querySelectorAll('.demo-button').forEach(btn => btn.classList.remove('active'));
203
+ button.classList.add('active');
204
+
205
+ currentPreset = key;
206
+ footer.loading = true;
207
+ setTimeout(() => {
208
+ applyPreset(preset);
209
+ footer.loading = false;
210
+ }, 500);
211
+ };
212
+ controls.appendChild(button);
213
+ });
214
+
215
+ wrapperElement.appendChild(controls);
216
+
217
+ // Add configuration display
218
+ const configDisplay = document.createElement('div');
219
+ configDisplay.className = 'config-display';
220
+ wrapperElement.appendChild(configDisplay);
221
+
222
+ const updateConfigDisplay = (config: any) => {
223
+ configDisplay.innerHTML = Object.entries(config)
224
+ .filter(([key]) => key !== 'socialLinks' && key !== 'additionalLinks' && key !== 'languageOptions')
225
+ .map(([key, value]) => `
226
+ <div class="config-item">
227
+ <div class="config-label">${key}</div>
228
+ <div class="config-value">${value}</div>
229
+ </div>
230
+ `).join('');
231
+ };
232
+
233
+ // Handle events
234
+ footer.addEventListener('footerLinkClick', (event: CustomEvent) => {
235
+ console.log('Footer link clicked:', event.detail);
236
+ alert(`Link clicked: ${event.detail.type} - ${event.detail.url}`);
237
+ });
238
+
239
+ footer.addEventListener('subscribeClick', () => {
240
+ alert('Subscribe feature would open here');
241
+ });
242
+
243
+ footer.addEventListener('reportIncidentClick', () => {
244
+ alert('Report incident form would open here');
245
+ });
246
+
247
+ footer.addEventListener('languageChange', (event: CustomEvent) => {
248
+ alert(`Language changed to: ${event.detail.language}`);
249
+ });
250
+ }}
251
+ >
252
+ <upl-statuspage-footer></upl-statuspage-footer>
253
+ </dees-demowrapper>
254
+ </div>
255
+
256
+ <!-- Loading and Error States -->
257
+ <div class="demo-section">
258
+ <div class="demo-title">Loading and Error States</div>
259
+ <dees-demowrapper
260
+ .runAfterRender=${async (wrapperElement: any) => {
261
+ const footer = wrapperElement.querySelector('upl-statuspage-footer') as any;
262
+
263
+ // Start with loading
264
+ footer.loading = true;
265
+ footer.companyName = 'LoadingCorp';
266
+
267
+ const controls = document.createElement('div');
268
+ controls.className = 'demo-controls';
269
+ controls.innerHTML = `
270
+ <button class="demo-button" id="toggleLoading">Toggle Loading</button>
271
+ <button class="demo-button" id="loadSuccess">Load Successfully</button>
272
+ <button class="demo-button" id="simulateError">Simulate Error</button>
273
+ <button class="demo-button" id="simulateOffline">Simulate Offline</button>
274
+ <button class="demo-button" id="brokenLinks">Broken Links</button>
275
+ `;
276
+ wrapperElement.appendChild(controls);
277
+
278
+ controls.querySelector('#toggleLoading')?.addEventListener('click', () => {
279
+ footer.loading = !footer.loading;
280
+ });
281
+
282
+ controls.querySelector('#loadSuccess')?.addEventListener('click', () => {
283
+ footer.loading = true;
284
+ setTimeout(() => {
285
+ footer.companyName = 'Successfully Loaded Inc';
286
+ footer.legalUrl = 'https://example.com/legal';
287
+ footer.supportEmail = 'support@loaded.com';
288
+ footer.statusPageUrl = 'https://status.loaded.com';
289
+ footer.lastUpdated = Date.now();
290
+ footer.socialLinks = [
291
+ { platform: 'twitter', url: 'https://twitter.com/loaded' },
292
+ { platform: 'github', url: 'https://github.com/loaded' }
293
+ ];
294
+ footer.loading = false;
295
+ footer.errorMessage = null;
296
+ }, 1000);
297
+ });
298
+
299
+ controls.querySelector('#simulateError')?.addEventListener('click', () => {
300
+ footer.loading = true;
301
+ setTimeout(() => {
302
+ footer.loading = false;
303
+ footer.errorMessage = 'Failed to load footer configuration';
304
+ footer.companyName = 'Error Loading';
305
+ footer.socialLinks = [];
306
+ }, 1500);
307
+ });
308
+
309
+ controls.querySelector('#simulateOffline')?.addEventListener('click', () => {
310
+ footer.offline = true;
311
+ footer.errorMessage = 'You are currently offline';
312
+ footer.lastUpdated = null;
313
+ });
314
+
315
+ controls.querySelector('#brokenLinks')?.addEventListener('click', () => {
316
+ footer.companyName = 'Broken Links Demo';
317
+ footer.legalUrl = 'https://broken.invalid/legal';
318
+ footer.supportEmail = 'invalid-email';
319
+ footer.socialLinks = [
320
+ { platform: 'twitter', url: '' },
321
+ { platform: 'github', url: 'not-a-url' }
322
+ ];
323
+ footer.rssFeedUrl = 'https://broken.invalid/rss';
324
+ footer.apiStatusUrl = null;
325
+ });
326
+
327
+ // Add info display
328
+ const info = document.createElement('div');
329
+ info.className = 'demo-info';
330
+ info.innerHTML = 'Test different loading states and error scenarios using the controls above.';
331
+ wrapperElement.appendChild(info);
332
+ }}
333
+ >
334
+ <upl-statuspage-footer></upl-statuspage-footer>
335
+ </dees-demowrapper>
336
+ </div>
337
+
338
+ <!-- Dynamic Updates and Real-time Features -->
339
+ <div class="demo-section">
340
+ <div class="demo-title">Dynamic Updates and Real-time Features</div>
341
+ <dees-demowrapper
342
+ .runAfterRender=${async (wrapperElement: any) => {
343
+ const footer = wrapperElement.querySelector('upl-statuspage-footer') as any;
344
+
345
+ // Initial configuration
346
+ footer.companyName = 'RealTime Systems';
347
+ footer.legalUrl = 'https://realtime.com/legal';
348
+ footer.supportEmail = 'support@realtime.com';
349
+ footer.statusPageUrl = 'https://status.realtime.com';
350
+ footer.lastUpdated = Date.now();
351
+ footer.currentYear = new Date().getFullYear();
352
+
353
+ // Dynamic social links
354
+ const allSocialPlatforms = [
355
+ { platform: 'twitter', url: 'https://twitter.com/realtime' },
356
+ { platform: 'github', url: 'https://github.com/realtime' },
357
+ { platform: 'linkedin', url: 'https://linkedin.com/company/realtime' },
358
+ { platform: 'facebook', url: 'https://facebook.com/realtime' },
359
+ { platform: 'youtube', url: 'https://youtube.com/realtime' },
360
+ { platform: 'instagram', url: 'https://instagram.com/realtime' },
361
+ { platform: 'slack', url: 'https://realtime.slack.com' },
362
+ { platform: 'discord', url: 'https://discord.gg/realtime' }
363
+ ];
364
+
365
+ footer.socialLinks = allSocialPlatforms.slice(0, 3);
366
+
367
+ // Real-time status feed
368
+ footer.rssFeedUrl = 'https://status.realtime.com/rss';
369
+ footer.apiStatusUrl = 'https://api.realtime.com/v1/status';
370
+
371
+ // Status feed simulation
372
+ const statusUpdates = [
373
+ 'All systems operational',
374
+ 'Investigating API latency',
375
+ 'Maintenance scheduled for tonight',
376
+ 'Performance improvements deployed',
377
+ 'New datacenter online',
378
+ 'Security patch applied'
379
+ ];
380
+
381
+ let updateIndex = 0;
382
+ footer.latestStatusUpdate = statusUpdates[0];
383
+
384
+ // Auto-update last updated time
385
+ const updateInterval = setInterval(() => {
386
+ footer.lastUpdated = Date.now();
387
+ }, 5000);
388
+
389
+ // Rotate status updates
390
+ const statusInterval = setInterval(() => {
391
+ updateIndex = (updateIndex + 1) % statusUpdates.length;
392
+ footer.latestStatusUpdate = statusUpdates[updateIndex];
393
+ logEvent(`Status update: ${statusUpdates[updateIndex]}`);
394
+ }, 8000);
395
+
396
+ // Create controls
397
+ const controls = document.createElement('div');
398
+ controls.className = 'demo-controls';
399
+ controls.innerHTML = `
400
+ <button class="demo-button" id="addSocial">Add Social Link</button>
401
+ <button class="demo-button" id="removeSocial">Remove Social Link</button>
402
+ <button class="demo-button" id="updateStatus">Force Status Update</button>
403
+ <button class="demo-button" id="changeYear">Change Year</button>
404
+ `;
405
+ wrapperElement.appendChild(controls);
406
+
407
+ controls.querySelector('#addSocial')?.addEventListener('click', () => {
408
+ if (footer.socialLinks.length < allSocialPlatforms.length) {
409
+ footer.socialLinks = [...footer.socialLinks, allSocialPlatforms[footer.socialLinks.length]];
410
+ logEvent(`Added ${allSocialPlatforms[footer.socialLinks.length - 1].platform} link`);
411
+ }
412
+ });
413
+
414
+ controls.querySelector('#removeSocial')?.addEventListener('click', () => {
415
+ if (footer.socialLinks.length > 0) {
416
+ const removed = footer.socialLinks[footer.socialLinks.length - 1];
417
+ footer.socialLinks = footer.socialLinks.slice(0, -1);
418
+ logEvent(`Removed ${removed.platform} link`);
419
+ }
420
+ });
421
+
422
+ controls.querySelector('#updateStatus')?.addEventListener('click', () => {
423
+ const customStatus = prompt('Enter custom status update:');
424
+ if (customStatus) {
425
+ footer.latestStatusUpdate = customStatus;
426
+ footer.lastUpdated = Date.now();
427
+ logEvent(`Custom status: ${customStatus}`);
428
+ }
429
+ });
430
+
431
+ controls.querySelector('#changeYear')?.addEventListener('click', () => {
432
+ footer.currentYear = footer.currentYear + 1;
433
+ logEvent(`Year changed to ${footer.currentYear}`);
434
+ });
435
+
436
+ // Event log
437
+ const eventLog = document.createElement('div');
438
+ eventLog.className = 'event-log';
439
+ eventLog.innerHTML = '<strong>Event Log:</strong><br>';
440
+ wrapperElement.appendChild(eventLog);
441
+
442
+ const logEvent = (message: string) => {
443
+ const time = new Date().toLocaleTimeString();
444
+ eventLog.innerHTML += `[${time}] ${message}<br>`;
445
+ eventLog.scrollTop = eventLog.scrollHeight;
446
+ };
447
+
448
+ logEvent('Real-time updates started');
449
+
450
+ // Cleanup
451
+ wrapperElement.addEventListener('remove', () => {
452
+ clearInterval(updateInterval);
453
+ clearInterval(statusInterval);
454
+ });
455
+ }}
456
+ >
457
+ <upl-statuspage-footer></upl-statuspage-footer>
458
+ </dees-demowrapper>
459
+ </div>
460
+
461
+ <!-- Interactive Features -->
462
+ <div class="demo-section">
463
+ <div class="demo-title">Interactive Features and Actions</div>
464
+ <dees-demowrapper
465
+ .runAfterRender=${async (wrapperElement: any) => {
466
+ const footer = wrapperElement.querySelector('upl-statuspage-footer') as any;
467
+
468
+ // Setup interactive footer
469
+ footer.companyName = 'Interactive Corp';
470
+ footer.legalUrl = 'https://interactive.com/legal';
471
+ footer.supportEmail = 'help@interactive.com';
472
+ footer.statusPageUrl = 'https://status.interactive.com';
473
+ footer.whitelabel = false;
474
+ footer.lastUpdated = Date.now();
475
+ footer.currentYear = new Date().getFullYear();
476
+
477
+ // Interactive features
478
+ footer.enableSubscribe = true;
479
+ footer.enableReportIssue = true;
480
+ footer.enableLanguageSelector = true;
481
+ footer.enableThemeToggle = true;
482
+
483
+ footer.languageOptions = [
484
+ { code: 'en', label: 'English' },
485
+ { code: 'es', label: 'Español' },
486
+ { code: 'fr', label: 'Français' },
487
+ { code: 'de', label: 'Deutsch' },
488
+ { code: 'ja', label: '日本語' },
489
+ { code: 'zh', label: '中文' }
490
+ ];
491
+
492
+ footer.socialLinks = [
493
+ { platform: 'twitter', url: 'https://twitter.com/interactive' },
494
+ { platform: 'github', url: 'https://github.com/interactive' },
495
+ { platform: 'discord', url: 'https://discord.gg/interactive' }
496
+ ];
497
+
498
+ footer.additionalLinks = [
499
+ { label: 'API Documentation', url: 'https://docs.interactive.com' },
500
+ { label: 'Service Level Agreement', url: 'https://interactive.com/sla' },
501
+ { label: 'Privacy Policy', url: 'https://interactive.com/privacy' },
502
+ { label: 'Terms of Service', url: 'https://interactive.com/terms' }
503
+ ];
504
+
505
+ // Subscribe functionality
506
+ let subscriberCount = 1234;
507
+ footer.subscriberCount = subscriberCount;
508
+
509
+ footer.addEventListener('subscribeClick', (event: CustomEvent) => {
510
+ const email = prompt('Enter your email to subscribe:');
511
+ if (email && email.includes('@')) {
512
+ subscriberCount++;
513
+ footer.subscriberCount = subscriberCount;
514
+ logAction(`New subscriber: ${email} (Total: ${subscriberCount})`);
515
+ alert(`Successfully subscribed! You are subscriber #${subscriberCount}`);
516
+ }
517
+ });
518
+
519
+ // Report issue functionality
520
+ footer.addEventListener('reportIncidentClick', (event: CustomEvent) => {
521
+ const issue = prompt('Describe the issue you are experiencing:');
522
+ if (issue) {
523
+ const ticketId = `INC-${Date.now().toString().slice(-6)}`;
524
+ logAction(`Issue reported: ${ticketId} - ${issue.substring(0, 50)}...`);
525
+ alert(`Thank you! Your issue has been logged.\nTicket ID: ${ticketId}\nWe will investigate and update you at the provided email.`);
526
+ }
527
+ });
528
+
529
+ // Language change
530
+ footer.addEventListener('languageChange', (event: CustomEvent) => {
531
+ const newLang = event.detail.language;
532
+ footer.currentLanguage = newLang;
533
+ logAction(`Language changed to: ${newLang}`);
534
+
535
+ // Simulate translation
536
+ const translations = {
537
+ en: 'Interactive Corp',
538
+ es: 'Corporación Interactiva',
539
+ fr: 'Corp Interactif',
540
+ de: 'Interaktive GmbH',
541
+ ja: 'インタラクティブ株式会社',
542
+ zh: '互动公司'
543
+ };
544
+
545
+ footer.companyName = translations[newLang] || translations.en;
546
+ });
547
+
548
+ // Theme toggle
549
+ footer.addEventListener('themeToggle', (event: CustomEvent) => {
550
+ const theme = event.detail.theme;
551
+ logAction(`Theme changed to: ${theme}`);
552
+ footer.currentTheme = theme;
553
+ });
554
+
555
+ // Click tracking
556
+ footer.addEventListener('footerLinkClick', (event: CustomEvent) => {
557
+ logAction(`Link clicked: ${event.detail.type} - ${event.detail.label || event.detail.url}`);
558
+ });
559
+
560
+ // Action log
561
+ const actionLog = document.createElement('div');
562
+ actionLog.className = 'event-log';
563
+ actionLog.innerHTML = '<strong>User Actions:</strong><br>';
564
+ wrapperElement.appendChild(actionLog);
565
+
566
+ const logAction = (message: string) => {
567
+ const time = new Date().toLocaleTimeString();
568
+ actionLog.innerHTML += `[${time}] ${message}<br>`;
569
+ actionLog.scrollTop = actionLog.scrollHeight;
570
+ };
571
+
572
+ logAction('Interactive footer ready');
573
+
574
+ // Add info
575
+ const info = document.createElement('div');
576
+ info.className = 'demo-info';
577
+ info.innerHTML = 'Try clicking on various footer elements to see the interactive features in action.';
578
+ wrapperElement.appendChild(info);
579
+ }}
580
+ >
581
+ <upl-statuspage-footer></upl-statuspage-footer>
582
+ </dees-demowrapper>
583
+ </div>
584
+
585
+ <!-- Edge Cases -->
586
+ <div class="demo-section">
587
+ <div class="demo-title">Edge Cases and Special Scenarios</div>
588
+ <dees-demowrapper
589
+ .runAfterRender=${async (wrapperElement: any) => {
590
+ const footer = wrapperElement.querySelector('upl-statuspage-footer') as any;
591
+
592
+ const edgeCases = {
593
+ empty: {
594
+ name: 'Empty/Minimal',
595
+ config: {
596
+ companyName: '',
597
+ whitelabel: true,
598
+ lastUpdated: null
599
+ }
600
+ },
601
+ veryLong: {
602
+ name: 'Very Long Content',
603
+ config: {
604
+ companyName: 'International Mega Corporation with an Extremely Long Company Name That Tests Layout Limits Inc.',
605
+ legalUrl: 'https://very-long-domain-name-that-might-break-layouts.international-corporation.com/legal/terms-and-conditions/privacy-policy/cookie-policy',
606
+ supportEmail: 'customer.support.team@very-long-domain-name.international-corporation.com',
607
+ socialLinks: Array.from({ length: 15 }, (_, i) => ({
608
+ platform: ['twitter', 'github', 'linkedin', 'facebook', 'youtube'][i % 5],
609
+ url: `https://social-${i}.com/long-username-handle-that-tests-limits`
610
+ })),
611
+ additionalLinks: Array.from({ length: 10 }, (_, i) => ({
612
+ label: `Very Long Link Label That Might Cause Layout Issues #${i + 1}`,
613
+ url: `https://example.com/very/long/path/structure/that/goes/on/and/on/page-${i}`
614
+ }))
615
+ }
616
+ },
617
+ unicode: {
618
+ name: 'Unicode/International',
619
+ config: {
620
+ companyName: '🌍 全球服务 • グローバル • العالمية • Глобальный 🌏',
621
+ legalUrl: 'https://unicode.test/法律',
622
+ supportEmail: 'support@日本.jp',
623
+ currentYear: new Date().getFullYear(),
624
+ socialLinks: [
625
+ { platform: 'twitter', url: 'https://twitter.com/🌐' },
626
+ { platform: 'github', url: 'https://github.com/世界' }
627
+ ],
628
+ additionalLinks: [
629
+ { label: '📋 Terms & Conditions', url: '#' },
630
+ { label: '🔒 Privacy Policy', url: '#' },
631
+ { label: '🛡️ Security', url: '#' }
632
+ ]
633
+ }
634
+ },
635
+ brokenData: {
636
+ name: 'Broken/Invalid Data',
637
+ config: {
638
+ companyName: null,
639
+ legalUrl: 'not-a-valid-url',
640
+ supportEmail: 'not-an-email',
641
+ currentYear: 'not-a-year',
642
+ lastUpdated: 'invalid-timestamp',
643
+ socialLinks: [
644
+ { platform: null, url: null },
645
+ { platform: 'unknown-platform', url: '' },
646
+ { url: 'https://missing-platform.com' },
647
+ { platform: 'twitter' }
648
+ ],
649
+ rssFeedUrl: '',
650
+ apiStatusUrl: undefined
651
+ }
652
+ },
653
+ maxData: {
654
+ name: 'Maximum Data',
655
+ config: {
656
+ companyName: 'Maximum Configuration Demo',
657
+ legalUrl: 'https://max.demo/legal',
658
+ supportEmail: 'all@max.demo',
659
+ statusPageUrl: 'https://status.max.demo',
660
+ whitelabel: false,
661
+ currentYear: new Date().getFullYear(),
662
+ lastUpdated: Date.now(),
663
+ language: 'en',
664
+ theme: 'dark',
665
+ socialLinks: Array.from({ length: 20 }, (_, i) => ({
666
+ platform: 'generic',
667
+ url: `https://social${i}.com`
668
+ })),
669
+ additionalLinks: Array.from({ length: 15 }, (_, i) => ({
670
+ label: `Link ${i + 1}`,
671
+ url: `#link${i + 1}`
672
+ })),
673
+ rssFeedUrl: 'https://status.max.demo/rss',
674
+ apiStatusUrl: 'https://api.max.demo/status',
675
+ subscriberCount: 999999,
676
+ enableSubscribe: true,
677
+ enableReportIssue: true,
678
+ enableLanguageSelector: true,
679
+ enableThemeToggle: true,
680
+ languageOptions: Array.from({ length: 50 }, (_, i) => ({
681
+ code: `lang${i}`,
682
+ label: `Language ${i}`
683
+ }))
684
+ }
685
+ }
686
+ };
687
+
688
+ // Initial setup
689
+ let currentCase = 'empty';
690
+ const applyCase = (edgeCase: any) => {
691
+ // Clear all properties first
692
+ Object.keys(footer).forEach(key => {
693
+ if (typeof footer[key] !== 'function') {
694
+ footer[key] = undefined;
695
+ }
696
+ });
697
+
698
+ // Apply new config
699
+ Object.keys(edgeCase.config).forEach(key => {
700
+ footer[key] = edgeCase.config[key];
701
+ });
702
+ };
703
+
704
+ applyCase(edgeCases[currentCase]);
705
+
706
+ // Create controls
707
+ const controls = document.createElement('div');
708
+ controls.className = 'demo-controls';
709
+
710
+ Object.entries(edgeCases).forEach(([key, edgeCase]) => {
711
+ const button = document.createElement('button');
712
+ button.className = 'demo-button' + (key === currentCase ? ' active' : '');
713
+ button.textContent = edgeCase.name;
714
+ button.onclick = () => {
715
+ controls.querySelectorAll('.demo-button').forEach(btn => btn.classList.remove('active'));
716
+ button.classList.add('active');
717
+
718
+ currentCase = key;
719
+ applyCase(edgeCase);
720
+ };
721
+ controls.appendChild(button);
722
+ });
723
+
724
+ wrapperElement.appendChild(controls);
725
+
726
+ // Add description
727
+ const info = document.createElement('div');
728
+ info.className = 'demo-info';
729
+ info.innerHTML = `
730
+ <strong>Edge Case Descriptions:</strong><br>
731
+ <strong>Empty:</strong> Minimal configuration with missing data<br>
732
+ <strong>Very Long:</strong> Tests layout with extremely long content<br>
733
+ <strong>Unicode:</strong> International characters and emojis<br>
734
+ <strong>Broken Data:</strong> Invalid or malformed configuration<br>
735
+ <strong>Maximum Data:</strong> All features with maximum content
736
+ `;
737
+ wrapperElement.appendChild(info);
738
+ }}
739
+ >
740
+ <upl-statuspage-footer></upl-statuspage-footer>
741
+ </dees-demowrapper>
742
+ </div>
743
+ </div>
744
+ `;