@uptime.link/statuspage 1.3.0 → 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.0",
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.0',
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;
293
+ }
294
+
295
+ .incident-meta-item {
296
+ display: flex;
297
+ align-items: center;
298
+ gap: 6px;
266
299
  }
267
300
 
268
- /* Pulse for investigating status */
269
- .incident-status.investigating .status-dot {
270
- animation: status-pulse 1.5s ease-in-out infinite;
301
+ .incident-meta-item dees-icon {
302
+ --icon-size: 12px;
303
+ --icon-color: ${sharedStyles.colors.text.muted};
271
304
  }
272
305
 
273
- @keyframes status-pulse {
274
- 0%, 100% { opacity: 1; transform: scale(1); }
275
- 50% { opacity: 0.6; transform: scale(1.2); }
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
 
@@ -351,22 +408,6 @@ export class UplStatuspageIncidents extends DeesElement {
351
408
  padding-left: 24px;
352
409
  }
353
410
 
354
- /* Vertical connector line */
355
- .timeline::before {
356
- content: '';
357
- position: absolute;
358
- left: 7px;
359
- top: 10px;
360
- bottom: calc(100% - 10px);
361
- height: auto;
362
- width: 2px;
363
- background: ${cssManager.bdTheme(
364
- 'linear-gradient(to bottom, #e5e7eb 0%, #d1d5db 50%, #e5e7eb 100%)',
365
- 'linear-gradient(to bottom, #27272a 0%, #3f3f46 50%, #27272a 100%)'
366
- )};
367
- border-radius: 1px;
368
- }
369
-
370
411
  .update-item {
371
412
  position: relative;
372
413
  padding-left: ${unsafeCSS(sharedStyles.spacing.lg)};
@@ -378,7 +419,16 @@ export class UplStatuspageIncidents extends DeesElement {
378
419
  padding-bottom: 0;
379
420
  }
380
421
 
381
- /* Timeline dot */
422
+ .update-item:not(:last-child)::after {
423
+ content: '';
424
+ position: absolute;
425
+ left: -15px;
426
+ top: 18px;
427
+ bottom: 0;
428
+ width: 2px;
429
+ background: ${sharedStyles.colors.border.default};
430
+ }
431
+
382
432
  .update-item::before {
383
433
  content: '';
384
434
  position: absolute;
@@ -532,54 +582,39 @@ export class UplStatuspageIncidents extends DeesElement {
532
582
  background: ${cssManager.bdTheme('#dcfce7', '#065f46')};
533
583
  }
534
584
 
535
- .collapsed-hint {
536
- font-size: 12px;
537
- color: ${sharedStyles.colors.text.secondary};
538
- text-align: center;
539
- margin-top: ${unsafeCSS(sharedStyles.spacing.md)};
540
- opacity: 0.8;
541
- }
542
-
543
- /* Expand icon animation */
544
- .expand-icon {
545
- transition: transform ${unsafeCSS(sharedStyles.durations.normal)} ${unsafeCSS(sharedStyles.easings.default)};
546
- }
547
-
548
- .expand-icon.rotated {
549
- transform: rotate(180deg);
550
- }
551
-
552
585
  @media (max-width: 640px) {
553
586
  .container {
554
587
  padding: 0 ${unsafeCSS(sharedStyles.spacing.md)} ${unsafeCSS(sharedStyles.spacing.md)} ${unsafeCSS(sharedStyles.spacing.md)};
555
588
  }
556
589
 
557
590
  .incident-header {
558
- padding: ${unsafeCSS(sharedStyles.spacing.md)};
591
+ padding: 12px;
559
592
  }
560
593
 
561
594
  .incident-body {
562
- padding: 0 ${unsafeCSS(sharedStyles.spacing.md)} ${unsafeCSS(sharedStyles.spacing.md)} ${unsafeCSS(sharedStyles.spacing.md)};
595
+ padding: 0 12px 12px 24px;
563
596
  }
564
597
 
565
598
  .incident-meta {
566
599
  flex-direction: column;
567
- gap: ${unsafeCSS(sharedStyles.spacing.xs)};
600
+ align-items: flex-start;
601
+ gap: 8px;
568
602
  }
569
603
 
570
604
  .timeline {
571
605
  padding-left: 20px;
572
606
  }
573
607
 
574
- .timeline::before {
575
- left: 4px;
576
- }
577
-
578
608
  .update-item::before {
579
609
  left: -18px;
580
610
  width: 10px;
581
611
  height: 10px;
582
612
  }
613
+
614
+ .update-item:not(:last-child)::after {
615
+ left: -12px;
616
+ top: 16px;
617
+ }
583
618
  }
584
619
  `,
585
620
  ];
@@ -595,16 +630,16 @@ export class UplStatuspageIncidents extends DeesElement {
595
630
  ` :
596
631
  html`<div class="noIncidentBox">No incidents ongoing.</div>`
597
632
  }
598
-
633
+
599
634
  <uplinternal-miniheading>Past Incidents</uplinternal-miniheading>
600
635
  ${this.loading ? html`
601
636
  <div class="loading-skeleton"></div>
602
637
  <div class="loading-skeleton"></div>
603
- ` : this.pastIncidents.length ?
638
+ ` : this.pastIncidents.length ?
604
639
  this.pastIncidents.slice(0, 5).map(incident => this.renderIncident(incident, false)) :
605
640
  html`<div class="noIncidentBox">No past incidents in the last ${this.daysToShow} days.</div>`
606
641
  }
607
-
642
+
608
643
  ${this.pastIncidents.length > 5 && !this.loading ? html`
609
644
  <div class="show-more">
610
645
  <button class="show-more-button" @click=${this.handleShowMore}>
@@ -623,74 +658,54 @@ export class UplStatuspageIncidents extends DeesElement {
623
658
  this.formatDuration(Date.now() - incident.startTime);
624
659
 
625
660
  const isActive = isCurrent && latestUpdate?.status !== 'resolved';
661
+ const isExpanded = this.expandedIncidents.has(incident.id);
626
662
 
627
663
  return html`
628
- <div class="incident-card ${this.expandedIncidents.has(incident.id) ? 'expanded' : ''} ${isActive ? 'active-incident' : ''}">
629
- <div class="incident-header ${incident.severity}" @click=${() => this.toggleIncident(incident.id)}>
630
- <div>
631
- <h3 class="incident-title">${incident.title}</h3>
632
- <div class="incident-meta">
633
- <span>Started: ${this.formatDate(incident.startTime)}</span>
634
- <span>Duration: ${duration}</span>
635
- ${incident.endTime ? html`
636
- <span>Ended: ${this.formatDate(incident.endTime)}</span>
637
- ` : ''}
638
- </div>
639
- ${!this.expandedIncidents.has(incident.id) ? html`
640
- <div style="
641
- margin-top: ${unsafeCSS(sharedStyles.spacing.sm)};
642
- font-size: 13px;
643
- color: ${sharedStyles.colors.text.secondary};
644
- display: flex;
645
- align-items: center;
646
- gap: ${unsafeCSS(sharedStyles.spacing.md)};
647
- ">
648
- ${incident.impact ? html`
649
- <span style="
650
- overflow: hidden;
651
- text-overflow: ellipsis;
652
- white-space: nowrap;
653
- max-width: 500px;
654
- ">${incident.impact}</span>
655
- ` : ''}
656
- <span style="
657
- font-size: 12px;
658
- color: ${cssManager.bdTheme('#9ca3af', '#71717a')};
659
- ">
660
- ${incident.updates.length} update${incident.updates.length !== 1 ? 's' : ''}
661
- </span>
662
- </div>
663
- ` : ''}
664
- </div>
665
- <div style="display: flex; align-items: center; gap: ${unsafeCSS(sharedStyles.spacing.md)};">
666
- <div class="incident-status ${latestUpdate.status}">
667
- ${this.getStatusIcon(latestUpdate.status)}
668
- ${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>
669
675
  </div>
670
- <div class="expand-icon" style="
671
- font-size: 10px;
672
- color: ${cssManager.bdTheme('#6b7280', '#a1a1aa')};
673
- transition: transform 0.2s ease;
674
- display: flex;
675
- align-items: center;
676
- justify-content: center;
677
- width: 24px;
678
- height: 24px;
679
- border-radius: 4px;
680
- background: ${cssManager.bdTheme('#f3f4f6', '#27272a')};
681
- ${this.expandedIncidents.has(incident.id) ? 'transform: rotate(180deg);' : ''}
682
- ">
683
-
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>
684
693
  </div>
685
694
  </div>
695
+
696
+ <button class="incident-expand ${isExpanded ? 'expanded' : ''}">
697
+ <dees-icon .icon=${'lucide:ChevronDown'} .iconSize=${16}></dees-icon>
698
+ </button>
686
699
  </div>
687
-
688
- ${this.expandedIncidents.has(incident.id) ? html`
700
+
701
+ ${isExpanded ? html`
689
702
  <div class="incident-body">
690
- <div class="incident-impact">
691
- <strong>Impact:</strong> ${incident.impact}
692
- </div>
693
-
703
+ ${incident.impact ? html`
704
+ <div class="incident-impact">
705
+ <strong>Impact:</strong> ${incident.impact}
706
+ </div>
707
+ ` : ''}
708
+
694
709
  ${incident.affectedServices.length > 0 ? html`
695
710
  <div class="affected-services">
696
711
  <div class="affected-services-title">Affected Services:</div>
@@ -699,7 +714,7 @@ export class UplStatuspageIncidents extends DeesElement {
699
714
  `)}
700
715
  </div>
701
716
  ` : ''}
702
-
717
+
703
718
  ${incident.updates.length > 0 ? html`
704
719
  <div class="incident-updates">
705
720
  <h4 class="updates-title">Updates</h4>
@@ -708,21 +723,21 @@ export class UplStatuspageIncidents extends DeesElement {
708
723
  </div>
709
724
  </div>
710
725
  ` : ''}
711
-
726
+
712
727
  ${incident.rootCause && isCurrent === false ? html`
713
728
  <div class="incident-impact" style="margin-top: 12px;">
714
729
  <strong>Root Cause:</strong> ${incident.rootCause}
715
730
  </div>
716
731
  ` : ''}
717
-
732
+
718
733
  ${incident.resolution && isCurrent === false ? html`
719
734
  <div class="incident-impact" style="margin-top: 12px;">
720
735
  <strong>Resolution:</strong> ${incident.resolution}
721
736
  </div>
722
737
  ` : ''}
723
-
738
+
724
739
  <div class="incident-actions">
725
- <button
740
+ <button
726
741
  class="subscribe-button ${this.isSubscribedToIncident(incident.id) ? 'subscribed' : ''}"
727
742
  @click=${(e: Event) => {
728
743
  e.stopPropagation();
@@ -730,15 +745,10 @@ export class UplStatuspageIncidents extends DeesElement {
730
745
  }}
731
746
  >
732
747
  ${this.isSubscribedToIncident(incident.id) ? html`
733
- <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
734
- <path d="M11.6667 3.5L5.25 9.91667L2.33334 7" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
735
- </svg>
748
+ <dees-icon .icon=${'lucide:Check'} .iconSize=${14}></dees-icon>
736
749
  Subscribed to updates
737
750
  ` : html`
738
- <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
739
- <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"/>
740
- <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"/>
741
- </svg>
751
+ <dees-icon .icon=${'lucide:Bell'} .iconSize=${14}></dees-icon>
742
752
  Subscribe to updates
743
753
  `}
744
754
  </button>
@@ -765,10 +775,7 @@ export class UplStatuspageIncidents extends DeesElement {
765
775
  <div class="update-message">${update.message}</div>
766
776
  ${update.author ? html`
767
777
  <div class="update-author">
768
- <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
769
- <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
770
- <circle cx="12" cy="7" r="4"></circle>
771
- </svg>
778
+ <dees-icon .icon=${'lucide:User'} .iconSize=${12}></dees-icon>
772
779
  ${update.author}
773
780
  </div>
774
781
  ` : ''}
@@ -776,45 +783,32 @@ export class UplStatuspageIncidents extends DeesElement {
776
783
  `;
777
784
  }
778
785
 
779
- private getStatusIcon(status: string): TemplateResult {
780
- return html`<span class="status-dot" style="
781
- display: inline-block;
782
- width: 6px;
783
- height: 6px;
784
- border-radius: 50%;
785
- background: ${status === 'resolved' ? sharedStyles.colors.status.operational :
786
- status === 'monitoring' ? sharedStyles.colors.status.maintenance :
787
- status === 'identified' ? sharedStyles.colors.status.degraded :
788
- sharedStyles.colors.status.partial};
789
- "></span>`;
790
- }
791
-
792
786
  private formatDate(timestamp: number): string {
793
787
  const date = new Date(timestamp);
794
788
  const now = Date.now();
795
789
  const diff = now - timestamp;
796
-
790
+
797
791
  // Less than 1 hour ago
798
792
  if (diff < 60 * 60 * 1000) {
799
793
  const minutes = Math.floor(diff / (60 * 1000));
800
794
  return `${minutes} minute${minutes !== 1 ? 's' : ''} ago`;
801
795
  }
802
-
796
+
803
797
  // Less than 24 hours ago
804
798
  if (diff < 24 * 60 * 60 * 1000) {
805
799
  const hours = Math.floor(diff / (60 * 60 * 1000));
806
800
  return `${hours} hour${hours !== 1 ? 's' : ''} ago`;
807
801
  }
808
-
802
+
809
803
  // Less than 7 days ago
810
804
  if (diff < 7 * 24 * 60 * 60 * 1000) {
811
805
  const days = Math.floor(diff / (24 * 60 * 60 * 1000));
812
806
  return `${days} day${days !== 1 ? 's' : ''} ago`;
813
807
  }
814
-
808
+
815
809
  // Default to full date
816
- return date.toLocaleDateString('en-US', {
817
- month: 'short',
810
+ return date.toLocaleDateString('en-US', {
811
+ month: 'short',
818
812
  day: 'numeric',
819
813
  year: date.getFullYear() !== new Date().getFullYear() ? 'numeric' : undefined
820
814
  });
@@ -824,7 +818,7 @@ export class UplStatuspageIncidents extends DeesElement {
824
818
  const minutes = Math.floor(milliseconds / (60 * 1000));
825
819
  const hours = Math.floor(minutes / 60);
826
820
  const days = Math.floor(hours / 24);
827
-
821
+
828
822
  if (days > 0) {
829
823
  return `${days}d ${hours % 24}h`;
830
824
  } else if (hours > 0) {
@@ -866,9 +860,9 @@ export class UplStatuspageIncidents extends DeesElement {
866
860
  if (newSubscribed.has(incident.id)) {
867
861
  newSubscribed.delete(incident.id);
868
862
  this.dispatchEvent(new CustomEvent('incidentUnsubscribe', {
869
- detail: {
863
+ detail: {
870
864
  incident,
871
- incidentId: incident.id
865
+ incidentId: incident.id
872
866
  },
873
867
  bubbles: true,
874
868
  composed: true
@@ -876,7 +870,7 @@ export class UplStatuspageIncidents extends DeesElement {
876
870
  } else {
877
871
  newSubscribed.add(incident.id);
878
872
  this.dispatchEvent(new CustomEvent('incidentSubscribe', {
879
- detail: {
873
+ detail: {
880
874
  incident,
881
875
  incidentId: incident.id,
882
876
  incidentTitle: incident.title,