feat(monitor/frontend): alert banner (one-amber-fill overlay, 30s auto-dismiss)
The only surface in the dashboard that uses amber as a fill color — the one-alarm-color rule reserves this paint for "look here." 48px strip in the alertbanner grid-area, dark text (--amber-fg #1a1a1a) on the amber fill for cross-room legibility, ellipsis on long messages, dismiss button at right. Returns null when the ui store has no currentAlert so the row collapses to zero and the center grid sits flush with the top strip. Auto-dismiss after 30s via setTimeout in useEffect; cleanup on unmount or alert change. role="alert" for screen readers. focus-visible outline 1px --amber-fg. Adds --amber-fg to ethos tokens — pairs explicitly with --amber so any future amber-fill surface uses the same dark text. Also cleans up an empty `//` line in the ethos comment block (stylelint scss/comment-no-empty).
This commit is contained in:
parent
5e33a4db22
commit
0ba29226a2
|
|
@ -0,0 +1,44 @@
|
|||
// ©AngelaMos | 2026
|
||||
// AlertBanner.module.scss
|
||||
|
||||
.banner {
|
||||
grid-area: alertbanner;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 48px;
|
||||
padding: 0 16px;
|
||||
background: var(--amber);
|
||||
color: var(--amber-fg);
|
||||
font-size: var(--type-body);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.message {
|
||||
flex: 1;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.dismiss {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
color: var(--amber-fg);
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: 1px solid var(--amber-fg);
|
||||
outline-offset: 1px;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
// ©AngelaMos | 2026
|
||||
// AlertBanner.tsx
|
||||
|
||||
import { useEffect } from 'react'
|
||||
import { FiX } from 'react-icons/fi'
|
||||
import { useUIStore } from '@/stores/ui'
|
||||
import styles from './AlertBanner.module.scss'
|
||||
|
||||
const AUTO_DISMISS_MS = 30_000
|
||||
|
||||
export function AlertBanner(): React.ReactElement | null {
|
||||
const alert = useUIStore((s) => s.currentAlert)
|
||||
const dismiss = useUIStore((s) => s.dismissAlert)
|
||||
|
||||
useEffect(() => {
|
||||
if (!alert) return
|
||||
const id = setTimeout(dismiss, AUTO_DISMISS_MS)
|
||||
return () => clearTimeout(id)
|
||||
}, [alert, dismiss])
|
||||
|
||||
if (!alert) return null
|
||||
|
||||
return (
|
||||
<aside className={styles.banner} role="alert">
|
||||
<span className={styles.message}>{alert.message}</span>
|
||||
<button
|
||||
type="button"
|
||||
className={styles.dismiss}
|
||||
onClick={dismiss}
|
||||
aria-label="Dismiss"
|
||||
>
|
||||
<FiX aria-hidden />
|
||||
</button>
|
||||
</aside>
|
||||
)
|
||||
}
|
||||
|
||||
AlertBanner.displayName = 'AlertBanner'
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
// ©AngelaMos | 2026
|
||||
// Dashboard.tsx
|
||||
|
||||
import { AlertBanner } from './AlertBanner'
|
||||
import styles from './Dashboard.module.scss'
|
||||
import { TopStrip } from './TopStrip'
|
||||
|
||||
|
|
@ -8,6 +9,7 @@ export function Dashboard(): React.ReactElement {
|
|||
return (
|
||||
<div className={styles.root}>
|
||||
<TopStrip />
|
||||
<AlertBanner />
|
||||
<main className={styles.grid}>
|
||||
<aside className={styles.left} />
|
||||
<section className={styles.center} />
|
||||
|
|
|
|||
|
|
@ -168,8 +168,7 @@ $container-2xl: 42rem;
|
|||
$container-full: 100%;
|
||||
|
||||
// ============================================================================
|
||||
// ETHOS TOKENS — operator-grade dashboard surface
|
||||
//
|
||||
// ETHOS TOKENS — operator-grade dashboard surface.
|
||||
// Per docs/design/ethos-reference.md (also mirrored in _ethos.scss).
|
||||
// Used by /pages/dashboard/, /pages/globe/, /pages/panels/. NOT used by
|
||||
// auth pages — those keep the template's SCSS variables above.
|
||||
|
|
@ -192,6 +191,7 @@ $container-full: 100%;
|
|||
// Accents — ONE green, ONE amber. That is all.
|
||||
--ok: #4ade80; // live / healthy / busy
|
||||
--amber: #f59e0b; // stale / breached / anomaly. NEVER for decoration.
|
||||
--amber-fg: #1a1a1a; // near-black text-on-amber pairing (alert banner only)
|
||||
|
||||
// Type
|
||||
--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
|
||||
|
|
|
|||
Loading…
Reference in New Issue