@uptime.link/statuspage 1.3.1 → 1.4.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uptime.link/statuspage",
3
- "version": "1.3.1",
3
+ "version": "1.4.0",
4
4
  "private": false,
5
5
  "description": "A catalog of web components for the UptimeLink dashboard.",
6
6
  "main": "dist_ts_web/index.js",
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@uptime.link/statuspage',
6
- version: '1.3.1',
6
+ version: '1.4.0',
7
7
  description: 'A catalog of web components for the UptimeLink dashboard.'
8
8
  }
@@ -20,6 +20,8 @@ declare global {
20
20
  }
21
21
  }
22
22
 
23
+ type TIncidentStatus = 'investigating' | 'identified' | 'monitoring' | 'resolved' | 'postmortem';
24
+
23
25
  @customElement('upl-statuspage-incidents')
24
26
  export class UplStatuspageIncidents extends DeesElement {
25
27
  // STATIC
@@ -68,6 +70,22 @@ export class UplStatuspageIncidents extends DeesElement {
68
70
  })
69
71
  private accessor subscribedIncidents: Set<string> = new Set();
70
72
 
73
+ private statusIcons: Record<TIncidentStatus, string> = {
74
+ investigating: 'lucide:Search',
75
+ identified: 'lucide:Target',
76
+ monitoring: 'lucide:Eye',
77
+ resolved: 'lucide:CheckCircle',
78
+ postmortem: 'lucide:FileText',
79
+ };
80
+
81
+ private statusLabels: Record<TIncidentStatus, string> = {
82
+ investigating: 'Investigating',
83
+ identified: 'Identified',
84
+ monitoring: 'Monitoring',
85
+ resolved: 'Resolved',
86
+ postmortem: 'Postmortem',
87
+ };
88
+
71
89
  constructor() {
72
90
  super();
73
91
  }
@@ -171,112 +189,151 @@ export class UplStatuspageIncidents extends DeesElement {
171
189
  }
172
190
  }
173
191
 
192
+ /* New header layout matching admin catalog */
174
193
  .incident-header {
175
- padding: ${unsafeCSS(sharedStyles.spacing.lg)} ${unsafeCSS(sharedStyles.spacing.xl)};
176
- border-left: 4px solid;
177
194
  display: flex;
178
- align-items: start;
179
- justify-content: space-between;
180
- gap: ${unsafeCSS(sharedStyles.spacing.md)};
195
+ align-items: flex-start;
196
+ gap: 16px;
197
+ padding: 16px;
181
198
  cursor: pointer;
182
199
  transition: background-color ${unsafeCSS(sharedStyles.durations.fast)} ${unsafeCSS(sharedStyles.easings.default)};
183
- position: relative;
184
200
  }
185
201
 
186
202
  .incident-header:hover {
187
203
  background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.02)', 'rgba(255, 255, 255, 0.02)')};
188
204
  }
189
205
 
190
- .incident-header.critical {
191
- border-left-color: ${sharedStyles.colors.status.major};
206
+ /* Internal severity bar (replacing border-left) */
207
+ .incident-severity {
208
+ width: 4px;
209
+ align-self: stretch;
210
+ border-radius: 2px;
211
+ flex-shrink: 0;
192
212
  }
193
213
 
194
- .incident-header.major {
195
- border-left-color: ${sharedStyles.colors.status.partial};
196
- }
214
+ .incident-severity.critical { background: ${sharedStyles.colors.status.major}; }
215
+ .incident-severity.major { background: ${sharedStyles.colors.status.partial}; }
216
+ .incident-severity.minor { background: ${sharedStyles.colors.status.degraded}; }
217
+ .incident-severity.maintenance { background: ${sharedStyles.colors.status.maintenance}; }
197
218
 
198
- .incident-header.minor {
199
- border-left-color: ${sharedStyles.colors.status.degraded};
219
+ .incident-main {
220
+ flex: 1;
221
+ min-width: 0;
200
222
  }
201
223
 
202
- .incident-header.maintenance {
203
- border-left-color: ${sharedStyles.colors.status.maintenance};
224
+ .incident-title-row {
225
+ display: flex;
226
+ align-items: center;
227
+ gap: 8px;
228
+ margin-bottom: 6px;
229
+ flex-wrap: wrap;
204
230
  }
205
231
 
206
232
  .incident-title {
207
- font-size: 17px;
233
+ font-size: 15px;
208
234
  font-weight: 600;
209
235
  margin: 0;
210
- line-height: 1.4;
211
- letter-spacing: -0.01em;
212
- }
213
-
214
- .incident-meta {
215
- display: flex;
216
- gap: ${unsafeCSS(sharedStyles.spacing.lg)};
217
- margin-top: ${unsafeCSS(sharedStyles.spacing.sm)};
218
- font-size: 13px;
219
- color: ${sharedStyles.colors.text.secondary};
220
- flex-wrap: wrap;
221
- }
222
-
223
- .incident-meta span {
224
- display: flex;
225
- align-items: center;
226
- gap: 4px;
236
+ color: ${sharedStyles.colors.text.primary};
227
237
  }
228
238
 
239
+ /* Status badge inline with title */
229
240
  .incident-status {
230
241
  display: inline-flex;
231
242
  align-items: center;
232
243
  gap: 6px;
233
- padding: 6px 12px;
234
- border-radius: ${unsafeCSS(sharedStyles.borderRadius.full)};
244
+ padding: 4px 10px;
235
245
  font-size: 11px;
236
- font-weight: 600;
246
+ font-weight: 500;
247
+ border-radius: 9999px;
237
248
  text-transform: uppercase;
238
- letter-spacing: 0.04em;
239
249
  flex-shrink: 0;
240
- transition: all ${unsafeCSS(sharedStyles.durations.fast)} ${unsafeCSS(sharedStyles.easings.default)};
250
+ }
251
+
252
+ .incident-status dees-icon {
253
+ --icon-size: 12px;
241
254
  }
242
255
 
243
256
  .incident-status.investigating {
244
- background: ${cssManager.bdTheme('#fef3c7', '#78350f')};
245
- color: ${cssManager.bdTheme('#92400e', '#fbbf24')};
257
+ background: ${cssManager.bdTheme('rgba(249, 115, 22, 0.1)', 'rgba(249, 115, 22, 0.2)')};
258
+ color: ${cssManager.bdTheme('#ea580c', '#fb923c')};
259
+ --icon-color: ${cssManager.bdTheme('#ea580c', '#fb923c')};
246
260
  }
247
261
 
248
262
  .incident-status.identified {
249
- background: ${cssManager.bdTheme('#e9d5ff', '#581c87')};
250
- color: ${cssManager.bdTheme('#6b21a8', '#d8b4fe')};
263
+ background: ${cssManager.bdTheme('rgba(234, 179, 8, 0.1)', 'rgba(234, 179, 8, 0.2)')};
264
+ color: ${cssManager.bdTheme('#ca8a04', '#facc15')};
265
+ --icon-color: ${cssManager.bdTheme('#ca8a04', '#facc15')};
251
266
  }
252
267
 
253
268
  .incident-status.monitoring {
254
- background: ${cssManager.bdTheme('#dbeafe', '#1e3a8a')};
255
- color: ${cssManager.bdTheme('#1e40af', '#93c5fd')};
269
+ background: ${cssManager.bdTheme('rgba(59, 130, 246, 0.1)', 'rgba(59, 130, 246, 0.2)')};
270
+ color: ${cssManager.bdTheme('#2563eb', '#60a5fa')};
271
+ --icon-color: ${cssManager.bdTheme('#2563eb', '#60a5fa')};
256
272
  }
257
273
 
258
274
  .incident-status.resolved {
259
- background: ${cssManager.bdTheme('#d1fae5', '#064e3b')};
260
- color: ${cssManager.bdTheme('#047857', '#6ee7b7')};
275
+ background: ${cssManager.bdTheme('rgba(34, 197, 94, 0.1)', 'rgba(34, 197, 94, 0.2)')};
276
+ color: ${cssManager.bdTheme('#16a34a', '#4ade80')};
277
+ --icon-color: ${cssManager.bdTheme('#16a34a', '#4ade80')};
261
278
  }
262
279
 
263
280
  .incident-status.postmortem {
264
- background: ${cssManager.bdTheme('#e5e7eb', '#374151')};
265
- color: ${cssManager.bdTheme('#4b5563', '#d1d5db')};
281
+ background: ${cssManager.bdTheme('rgba(168, 85, 247, 0.1)', 'rgba(168, 85, 247, 0.2)')};
282
+ color: ${cssManager.bdTheme('#9333ea', '#c084fc')};
283
+ --icon-color: ${cssManager.bdTheme('#9333ea', '#c084fc')};
284
+ }
285
+
286
+ .incident-meta {
287
+ display: flex;
288
+ align-items: center;
289
+ gap: 16px;
290
+ font-size: 12px;
291
+ color: ${sharedStyles.colors.text.secondary};
292
+ flex-wrap: wrap;
266
293
  }
267
294
 
268
- /* Pulse for investigating status */
269
- .incident-status.investigating .status-dot {
270
- animation: status-pulse 1.5s ease-in-out infinite;
295
+ .incident-meta-item {
296
+ display: flex;
297
+ align-items: center;
298
+ gap: 6px;
271
299
  }
272
300
 
273
- @keyframes status-pulse {
274
- 0%, 100% { opacity: 1; transform: scale(1); }
275
- 50% { opacity: 0.6; transform: scale(1.2); }
301
+ .incident-meta-item dees-icon {
302
+ --icon-size: 12px;
303
+ --icon-color: ${sharedStyles.colors.text.muted};
304
+ }
305
+
306
+ .incident-expand {
307
+ width: 28px;
308
+ height: 28px;
309
+ display: flex;
310
+ align-items: center;
311
+ justify-content: center;
312
+ background: transparent;
313
+ border: none;
314
+ border-radius: 4px;
315
+ cursor: pointer;
316
+ color: ${sharedStyles.colors.text.muted};
317
+ transition: all ${unsafeCSS(sharedStyles.durations.fast)} ${unsafeCSS(sharedStyles.easings.default)};
318
+ flex-shrink: 0;
319
+ }
320
+
321
+ .incident-expand:hover {
322
+ background: ${sharedStyles.colors.background.muted};
323
+ color: ${sharedStyles.colors.text.primary};
324
+ }
325
+
326
+ .incident-expand dees-icon {
327
+ --icon-size: 16px;
328
+ transition: transform ${unsafeCSS(sharedStyles.durations.fast)} ${unsafeCSS(sharedStyles.easings.default)};
329
+ }
330
+
331
+ .incident-expand.expanded dees-icon {
332
+ transform: rotate(180deg);
276
333
  }
277
334
 
278
335
  .incident-body {
279
- padding: 0 ${unsafeCSS(sharedStyles.spacing.xl)} ${unsafeCSS(sharedStyles.spacing.xl)} ${unsafeCSS(sharedStyles.spacing.xl)};
336
+ padding: 0 16px 16px 36px;
280
337
  animation: slideDown 0.3s ${unsafeCSS(sharedStyles.easings.default)};
281
338
  }
282
339
 
@@ -362,8 +419,6 @@ export class UplStatuspageIncidents extends DeesElement {
362
419
  padding-bottom: 0;
363
420
  }
364
421
 
365
- /* Vertical connector line from each dot to the next */
366
- /* Dot: left -22px, width 12px + border 2px*2 = 16px total, center at -14px */
367
422
  .update-item:not(:last-child)::after {
368
423
  content: '';
369
424
  position: absolute;
@@ -374,7 +429,6 @@ export class UplStatuspageIncidents extends DeesElement {
374
429
  background: ${sharedStyles.colors.border.default};
375
430
  }
376
431
 
377
- /* Timeline dot */
378
432
  .update-item::before {
379
433
  content: '';
380
434
  position: absolute;
@@ -528,39 +582,23 @@ export class UplStatuspageIncidents extends DeesElement {
528
582
  background: ${cssManager.bdTheme('#dcfce7', '#065f46')};
529
583
  }
530
584
 
531
- .collapsed-hint {
532
- font-size: 12px;
533
- color: ${sharedStyles.colors.text.secondary};
534
- text-align: center;
535
- margin-top: ${unsafeCSS(sharedStyles.spacing.md)};
536
- opacity: 0.8;
537
- }
538
-
539
- /* Expand icon animation */
540
- .expand-icon {
541
- transition: transform ${unsafeCSS(sharedStyles.durations.normal)} ${unsafeCSS(sharedStyles.easings.default)};
542
- }
543
-
544
- .expand-icon.rotated {
545
- transform: rotate(180deg);
546
- }
547
-
548
585
  @media (max-width: 640px) {
549
586
  .container {
550
587
  padding: 0 ${unsafeCSS(sharedStyles.spacing.md)} ${unsafeCSS(sharedStyles.spacing.md)} ${unsafeCSS(sharedStyles.spacing.md)};
551
588
  }
552
589
 
553
590
  .incident-header {
554
- padding: ${unsafeCSS(sharedStyles.spacing.md)};
591
+ padding: 12px;
555
592
  }
556
593
 
557
594
  .incident-body {
558
- padding: 0 ${unsafeCSS(sharedStyles.spacing.md)} ${unsafeCSS(sharedStyles.spacing.md)} ${unsafeCSS(sharedStyles.spacing.md)};
595
+ padding: 0 12px 12px 24px;
559
596
  }
560
597
 
561
598
  .incident-meta {
562
599
  flex-direction: column;
563
- gap: ${unsafeCSS(sharedStyles.spacing.xs)};
600
+ align-items: flex-start;
601
+ gap: 8px;
564
602
  }
565
603
 
566
604
  .timeline {
@@ -573,7 +611,6 @@ export class UplStatuspageIncidents extends DeesElement {
573
611
  height: 10px;
574
612
  }
575
613
 
576
- /* Mobile dot: left -18px, width 10px + border 2px*2 = 14px, center at -11px */
577
614
  .update-item:not(:last-child)::after {
578
615
  left: -12px;
579
616
  top: 16px;
@@ -593,16 +630,16 @@ export class UplStatuspageIncidents extends DeesElement {
593
630
  ` :
594
631
  html`<div class="noIncidentBox">No incidents ongoing.</div>`
595
632
  }
596
-
633
+
597
634
  <uplinternal-miniheading>Past Incidents</uplinternal-miniheading>
598
635
  ${this.loading ? html`
599
636
  <div class="loading-skeleton"></div>
600
637
  <div class="loading-skeleton"></div>
601
- ` : this.pastIncidents.length ?
638
+ ` : this.pastIncidents.length ?
602
639
  this.pastIncidents.slice(0, 5).map(incident => this.renderIncident(incident, false)) :
603
640
  html`<div class="noIncidentBox">No past incidents in the last ${this.daysToShow} days.</div>`
604
641
  }
605
-
642
+
606
643
  ${this.pastIncidents.length > 5 && !this.loading ? html`
607
644
  <div class="show-more">
608
645
  <button class="show-more-button" @click=${this.handleShowMore}>
@@ -621,74 +658,54 @@ export class UplStatuspageIncidents extends DeesElement {
621
658
  this.formatDuration(Date.now() - incident.startTime);
622
659
 
623
660
  const isActive = isCurrent && latestUpdate?.status !== 'resolved';
661
+ const isExpanded = this.expandedIncidents.has(incident.id);
624
662
 
625
663
  return html`
626
- <div class="incident-card ${this.expandedIncidents.has(incident.id) ? 'expanded' : ''} ${isActive ? 'active-incident' : ''}">
627
- <div class="incident-header ${incident.severity}" @click=${() => this.toggleIncident(incident.id)}>
628
- <div>
629
- <h3 class="incident-title">${incident.title}</h3>
630
- <div class="incident-meta">
631
- <span>Started: ${this.formatDate(incident.startTime)}</span>
632
- <span>Duration: ${duration}</span>
633
- ${incident.endTime ? html`
634
- <span>Ended: ${this.formatDate(incident.endTime)}</span>
635
- ` : ''}
636
- </div>
637
- ${!this.expandedIncidents.has(incident.id) ? html`
638
- <div style="
639
- margin-top: ${unsafeCSS(sharedStyles.spacing.sm)};
640
- font-size: 13px;
641
- color: ${sharedStyles.colors.text.secondary};
642
- display: flex;
643
- align-items: center;
644
- gap: ${unsafeCSS(sharedStyles.spacing.md)};
645
- ">
646
- ${incident.impact ? html`
647
- <span style="
648
- overflow: hidden;
649
- text-overflow: ellipsis;
650
- white-space: nowrap;
651
- max-width: 500px;
652
- ">${incident.impact}</span>
653
- ` : ''}
654
- <span style="
655
- font-size: 12px;
656
- color: ${cssManager.bdTheme('#9ca3af', '#71717a')};
657
- ">
658
- ${incident.updates.length} update${incident.updates.length !== 1 ? 's' : ''}
659
- </span>
660
- </div>
661
- ` : ''}
662
- </div>
663
- <div style="display: flex; align-items: center; gap: ${unsafeCSS(sharedStyles.spacing.md)};">
664
- <div class="incident-status ${latestUpdate.status}">
665
- ${this.getStatusIcon(latestUpdate.status)}
666
- ${latestUpdate.status.replace(/_/g, ' ')}
664
+ <div class="incident-card ${isExpanded ? 'expanded' : ''} ${isActive ? 'active-incident' : ''}">
665
+ <div class="incident-header" @click=${() => this.toggleIncident(incident.id)}>
666
+ <div class="incident-severity ${incident.severity}"></div>
667
+
668
+ <div class="incident-main">
669
+ <div class="incident-title-row">
670
+ <h3 class="incident-title">${incident.title}</h3>
671
+ <span class="incident-status ${latestUpdate.status}">
672
+ <dees-icon .icon=${this.statusIcons[latestUpdate.status as TIncidentStatus]} .iconSize=${12}></dees-icon>
673
+ ${this.statusLabels[latestUpdate.status as TIncidentStatus] || latestUpdate.status}
674
+ </span>
667
675
  </div>
668
- <div class="expand-icon" style="
669
- font-size: 10px;
670
- color: ${cssManager.bdTheme('#6b7280', '#a1a1aa')};
671
- transition: transform 0.2s ease;
672
- display: flex;
673
- align-items: center;
674
- justify-content: center;
675
- width: 24px;
676
- height: 24px;
677
- border-radius: 4px;
678
- background: ${cssManager.bdTheme('#f3f4f6', '#27272a')};
679
- ${this.expandedIncidents.has(incident.id) ? 'transform: rotate(180deg);' : ''}
680
- ">
681
-
676
+ <div class="incident-meta">
677
+ <span class="incident-meta-item">
678
+ <dees-icon .icon=${'lucide:Calendar'} .iconSize=${12}></dees-icon>
679
+ ${this.formatDate(incident.startTime)}
680
+ </span>
681
+ <span class="incident-meta-item">
682
+ <dees-icon .icon=${'lucide:Clock'} .iconSize=${12}></dees-icon>
683
+ ${duration}
684
+ </span>
685
+ <span class="incident-meta-item">
686
+ <dees-icon .icon=${'lucide:Server'} .iconSize=${12}></dees-icon>
687
+ ${incident.affectedServices.length} service${incident.affectedServices.length !== 1 ? 's' : ''}
688
+ </span>
689
+ <span class="incident-meta-item">
690
+ <dees-icon .icon=${'lucide:MessageSquare'} .iconSize=${12}></dees-icon>
691
+ ${incident.updates.length} update${incident.updates.length !== 1 ? 's' : ''}
692
+ </span>
682
693
  </div>
683
694
  </div>
695
+
696
+ <button class="incident-expand ${isExpanded ? 'expanded' : ''}">
697
+ <dees-icon .icon=${'lucide:ChevronDown'} .iconSize=${16}></dees-icon>
698
+ </button>
684
699
  </div>
685
-
686
- ${this.expandedIncidents.has(incident.id) ? html`
700
+
701
+ ${isExpanded ? html`
687
702
  <div class="incident-body">
688
- <div class="incident-impact">
689
- <strong>Impact:</strong> ${incident.impact}
690
- </div>
691
-
703
+ ${incident.impact ? html`
704
+ <div class="incident-impact">
705
+ <strong>Impact:</strong> ${incident.impact}
706
+ </div>
707
+ ` : ''}
708
+
692
709
  ${incident.affectedServices.length > 0 ? html`
693
710
  <div class="affected-services">
694
711
  <div class="affected-services-title">Affected Services:</div>
@@ -697,7 +714,7 @@ export class UplStatuspageIncidents extends DeesElement {
697
714
  `)}
698
715
  </div>
699
716
  ` : ''}
700
-
717
+
701
718
  ${incident.updates.length > 0 ? html`
702
719
  <div class="incident-updates">
703
720
  <h4 class="updates-title">Updates</h4>
@@ -706,21 +723,21 @@ export class UplStatuspageIncidents extends DeesElement {
706
723
  </div>
707
724
  </div>
708
725
  ` : ''}
709
-
726
+
710
727
  ${incident.rootCause && isCurrent === false ? html`
711
728
  <div class="incident-impact" style="margin-top: 12px;">
712
729
  <strong>Root Cause:</strong> ${incident.rootCause}
713
730
  </div>
714
731
  ` : ''}
715
-
732
+
716
733
  ${incident.resolution && isCurrent === false ? html`
717
734
  <div class="incident-impact" style="margin-top: 12px;">
718
735
  <strong>Resolution:</strong> ${incident.resolution}
719
736
  </div>
720
737
  ` : ''}
721
-
738
+
722
739
  <div class="incident-actions">
723
- <button
740
+ <button
724
741
  class="subscribe-button ${this.isSubscribedToIncident(incident.id) ? 'subscribed' : ''}"
725
742
  @click=${(e: Event) => {
726
743
  e.stopPropagation();
@@ -728,15 +745,10 @@ export class UplStatuspageIncidents extends DeesElement {
728
745
  }}
729
746
  >
730
747
  ${this.isSubscribedToIncident(incident.id) ? html`
731
- <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
732
- <path d="M11.6667 3.5L5.25 9.91667L2.33334 7" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
733
- </svg>
748
+ <dees-icon .icon=${'lucide:Check'} .iconSize=${14}></dees-icon>
734
749
  Subscribed to updates
735
750
  ` : html`
736
- <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
737
- <path d="M10.5 5.25V8.75C10.5 9.34674 10.2629 9.91903 9.84099 10.341C9.41903 10.7629 8.84674 11 8.25 11L3.75 11C3.15326 11 2.58097 10.7629 2.15901 10.341C1.73705 9.91903 1.5 9.34674 1.5 8.75V4.25C1.5 3.65326 1.73705 3.08097 2.15901 2.65901C2.58097 2.23705 3.15326 2 3.75 2H7.25" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
738
- <path d="M9 1.5H12.5M12.5 1.5V5M12.5 1.5L6 8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
739
- </svg>
751
+ <dees-icon .icon=${'lucide:Bell'} .iconSize=${14}></dees-icon>
740
752
  Subscribe to updates
741
753
  `}
742
754
  </button>
@@ -763,10 +775,7 @@ export class UplStatuspageIncidents extends DeesElement {
763
775
  <div class="update-message">${update.message}</div>
764
776
  ${update.author ? html`
765
777
  <div class="update-author">
766
- <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
767
- <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
768
- <circle cx="12" cy="7" r="4"></circle>
769
- </svg>
778
+ <dees-icon .icon=${'lucide:User'} .iconSize=${12}></dees-icon>
770
779
  ${update.author}
771
780
  </div>
772
781
  ` : ''}
@@ -774,45 +783,32 @@ export class UplStatuspageIncidents extends DeesElement {
774
783
  `;
775
784
  }
776
785
 
777
- private getStatusIcon(status: string): TemplateResult {
778
- return html`<span class="status-dot" style="
779
- display: inline-block;
780
- width: 6px;
781
- height: 6px;
782
- border-radius: 50%;
783
- background: ${status === 'resolved' ? sharedStyles.colors.status.operational :
784
- status === 'monitoring' ? sharedStyles.colors.status.maintenance :
785
- status === 'identified' ? sharedStyles.colors.status.degraded :
786
- sharedStyles.colors.status.partial};
787
- "></span>`;
788
- }
789
-
790
786
  private formatDate(timestamp: number): string {
791
787
  const date = new Date(timestamp);
792
788
  const now = Date.now();
793
789
  const diff = now - timestamp;
794
-
790
+
795
791
  // Less than 1 hour ago
796
792
  if (diff < 60 * 60 * 1000) {
797
793
  const minutes = Math.floor(diff / (60 * 1000));
798
794
  return `${minutes} minute${minutes !== 1 ? 's' : ''} ago`;
799
795
  }
800
-
796
+
801
797
  // Less than 24 hours ago
802
798
  if (diff < 24 * 60 * 60 * 1000) {
803
799
  const hours = Math.floor(diff / (60 * 60 * 1000));
804
800
  return `${hours} hour${hours !== 1 ? 's' : ''} ago`;
805
801
  }
806
-
802
+
807
803
  // Less than 7 days ago
808
804
  if (diff < 7 * 24 * 60 * 60 * 1000) {
809
805
  const days = Math.floor(diff / (24 * 60 * 60 * 1000));
810
806
  return `${days} day${days !== 1 ? 's' : ''} ago`;
811
807
  }
812
-
808
+
813
809
  // Default to full date
814
- return date.toLocaleDateString('en-US', {
815
- month: 'short',
810
+ return date.toLocaleDateString('en-US', {
811
+ month: 'short',
816
812
  day: 'numeric',
817
813
  year: date.getFullYear() !== new Date().getFullYear() ? 'numeric' : undefined
818
814
  });
@@ -822,7 +818,7 @@ export class UplStatuspageIncidents extends DeesElement {
822
818
  const minutes = Math.floor(milliseconds / (60 * 1000));
823
819
  const hours = Math.floor(minutes / 60);
824
820
  const days = Math.floor(hours / 24);
825
-
821
+
826
822
  if (days > 0) {
827
823
  return `${days}d ${hours % 24}h`;
828
824
  } else if (hours > 0) {
@@ -864,9 +860,9 @@ export class UplStatuspageIncidents extends DeesElement {
864
860
  if (newSubscribed.has(incident.id)) {
865
861
  newSubscribed.delete(incident.id);
866
862
  this.dispatchEvent(new CustomEvent('incidentUnsubscribe', {
867
- detail: {
863
+ detail: {
868
864
  incident,
869
- incidentId: incident.id
865
+ incidentId: incident.id
870
866
  },
871
867
  bubbles: true,
872
868
  composed: true
@@ -874,7 +870,7 @@ export class UplStatuspageIncidents extends DeesElement {
874
870
  } else {
875
871
  newSubscribed.add(incident.id);
876
872
  this.dispatchEvent(new CustomEvent('incidentSubscribe', {
877
- detail: {
873
+ detail: {
878
874
  incident,
879
875
  incidentId: incident.id,
880
876
  incidentTitle: incident.title,