feat: add SLA banner component and gradient progress bar fills from design test
Lint / JS (eslint) (push) Successful in 8s

SLA banners (.lt-sla-p1 / .lt-sla-p2):
- P1 pulsing red banner with lt-sla-pulse keyframe
- P2 static amber banner
- Subcomponents: lt-sla-icon, lt-sla-info, lt-sla-title, lt-sla-bar,
  lt-sla-fill, lt-sla-meta, lt-sla-dismiss
- Light theme overrides included
- Demo section added to base.html with dismiss wiring

Progress bar gradient fills:
- Default (orange), --cyan, --green, --red variants now use
  linear-gradient fills instead of flat accent colors for more
  dramatic terminal readout appearance

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-29 17:18:33 -04:00
parent 8f2f310fe2
commit 39862fab3b
2 changed files with 110 additions and 5 deletions
+79 -5
View File
@@ -2438,7 +2438,7 @@ select option:checked {
}
.lt-progress-bar {
height: 100%;
background: var(--accent-orange);
background: linear-gradient(90deg, var(--accent-orange), #ff8c2b);
box-shadow: var(--glow-orange);
transition: width 0.4s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
@@ -2451,9 +2451,9 @@ select option:checked {
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.4));
}
.lt-progress--cyan .lt-progress-bar { background: var(--accent-cyan); box-shadow: var(--glow-cyan); }
.lt-progress--green .lt-progress-bar { background: var(--accent-green); box-shadow: var(--glow-green); }
.lt-progress--red .lt-progress-bar { background: var(--accent-red); box-shadow: var(--glow-red); }
.lt-progress--cyan .lt-progress-bar { background: linear-gradient(90deg, var(--accent-cyan), #33dfff); box-shadow: var(--glow-cyan); }
.lt-progress--green .lt-progress-bar { background: linear-gradient(90deg, var(--accent-green), #33ffaa); box-shadow: var(--glow-green); }
.lt-progress--red .lt-progress-bar { background: linear-gradient(90deg, var(--accent-red), #ff4466); box-shadow: var(--glow-red); }
.lt-progress--striped .lt-progress-bar {
background-image: repeating-linear-gradient(
45deg, transparent, transparent 4px,
@@ -4429,7 +4429,81 @@ body.lt-is-offline .lt-main { margin-top: 2rem; transition: margin-top 0.25s eas
/* ----------------------------------------------------------------
61. TIMELINE / ACTIVITY FEED
61. SLA BANNER
----------------------------------------------------------------
lt-sla-p1 — pulsing red banner for critical SLA breach
lt-sla-p2 — static amber banner for high-priority SLA warning
---------------------------------------------------------------- */
.lt-sla-p1,
.lt-sla-p2 {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.6rem 1rem;
border: 1px solid;
font-family: var(--font-mono);
}
.lt-sla-p1 {
border-color: rgba(255,45,85,0.4);
background: rgba(255,45,85,0.08);
animation: lt-sla-pulse 2s infinite;
}
.lt-sla-p2 {
border-color: rgba(255,179,0,0.4);
background: rgba(255,179,0,0.08);
}
@keyframes lt-sla-pulse {
0%, 100% { box-shadow: 0 0 8px rgba(255,45,85,0.20); }
50% { box-shadow: 0 0 20px rgba(255,45,85,0.45); }
}
.lt-sla-icon { font-size: 1rem; flex-shrink: 0; }
.lt-sla-info { flex: 1; min-width: 0; }
.lt-sla-title {
font-size: 0.68rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.12em;
margin-bottom: 4px;
}
.lt-sla-p1 .lt-sla-title { color: var(--accent-red); text-shadow: var(--glow-red); }
.lt-sla-p2 .lt-sla-title { color: var(--accent-amber); text-shadow: var(--glow-amber); }
.lt-sla-bar {
height: 5px;
background: rgba(255,255,255,0.08);
position: relative;
overflow: hidden;
}
.lt-sla-fill {
height: 100%;
width: 0%;
transition: width 0.4s ease;
}
.lt-sla-p1 .lt-sla-fill { background: linear-gradient(90deg, var(--accent-red), var(--accent-orange)); box-shadow: 0 0 8px rgba(255,45,85,0.6); }
.lt-sla-p2 .lt-sla-fill { background: var(--accent-amber); box-shadow: 0 0 8px rgba(255,179,0,0.6); }
.lt-sla-meta {
font-size: 0.60rem;
color: var(--text-dim);
text-transform: uppercase;
letter-spacing: 0.10em;
flex-shrink: 0;
}
.lt-sla-dismiss {
font-size: 0.70rem;
color: var(--text-dim);
cursor: pointer;
background: none;
border: none;
flex-shrink: 0;
padding: 0 0.25rem;
font-family: var(--font-mono);
}
.lt-sla-dismiss:hover { color: var(--text-secondary); }
html[data-theme="light"] .lt-sla-p1 { background: rgba(180,30,50,0.06); border-color: rgba(180,30,50,0.35); }
html[data-theme="light"] .lt-sla-p2 { background: rgba(138,90,0,0.06); border-color: rgba(138,90,0,0.35); }
/* ----------------------------------------------------------------
62. TIMELINE / ACTIVITY FEED
---------------------------------------------------------------- */
.lt-timeline {
display: flex;
+31
View File
@@ -932,6 +932,29 @@
</div>
</div>
<!-- SLA BANNERS -->
<div class="lt-section-header">SLA Banners</div>
<div class="lt-section-body" style="display:flex;flex-direction:column;gap:var(--space-sm)">
<div class="lt-sla-p1" role="alert">
<span class="lt-sla-icon" aria-hidden="true">🔴</span>
<div class="lt-sla-info">
<div class="lt-sla-title">⚠ P1 Critical — SLA: 6h 42m elapsed of 8h limit</div>
<div class="lt-sla-bar"><div class="lt-sla-fill" style="width:84%"></div></div>
</div>
<div class="lt-sla-meta">Storage array link-down · #123456789</div>
<button type="button" class="lt-sla-dismiss" aria-label="Dismiss"></button>
</div>
<div class="lt-sla-p2" role="alert">
<span class="lt-sla-icon" aria-hidden="true">🟠</span>
<div class="lt-sla-info">
<div class="lt-sla-title">P2 High — SLA: 9h 37m elapsed of 24h limit</div>
<div class="lt-sla-bar"><div class="lt-sla-fill" style="width:40%"></div></div>
</div>
<div class="lt-sla-meta">Switch port flapping · #987654321</div>
<button type="button" class="lt-sla-dismiss" aria-label="Dismiss"></button>
</div>
</div>
<!-- TOGGLES, RANGE, TAGS -->
<div class="lt-section-header">Toggles / Range / Tags</div>
<div class="lt-section-body" style="display:flex;flex-direction:column;gap:var(--space-lg)">
@@ -1978,6 +2001,14 @@ Storage array link-down on `compute-storage-01`.
});
});
// SLA dismiss buttons
document.querySelectorAll('.lt-sla-dismiss').forEach(btn => {
btn.addEventListener('click', () => {
const banner = btn.closest('.lt-sla-p1, .lt-sla-p2');
if (banner) banner.remove();
});
});
// Footer year
const footerYear = document.getElementById('footer-year');
if (footerYear) footerYear.textContent = new Date().getFullYear();