diff --git a/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/pages/dashboard/BottomTicker.module.scss b/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/pages/dashboard/BottomTicker.module.scss new file mode 100644 index 00000000..496358b8 --- /dev/null +++ b/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/pages/dashboard/BottomTicker.module.scss @@ -0,0 +1,48 @@ +// ©AngelaMos | 2026 +// BottomTicker.module.scss + +.ticker { + grid-area: bottomticker; + height: 32px; + border-top: 1px solid var(--fg-4); + background: var(--bg); + overflow: hidden; + position: relative; +} + +.track { + display: flex; + align-items: center; + height: 100%; + gap: 24px; + padding-left: 100%; + white-space: nowrap; + animation: ticker-scroll 60s linear infinite; +} + +@keyframes ticker-scroll { + to { + transform: translateX(-100%); + } +} + +.item { + display: inline-flex; + align-items: center; + gap: 8px; + font-size: var(--type-body); + color: var(--fg-2); +} + +.source { + font-size: var(--type-label); + letter-spacing: var(--letter-spacing-label); + color: var(--fg-3); + text-transform: uppercase; +} + +.ts { + font-family: var(--font-mono); + color: var(--fg-3); + font-variant-numeric: tabular-nums; +} diff --git a/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/pages/dashboard/BottomTicker.tsx b/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/pages/dashboard/BottomTicker.tsx new file mode 100644 index 00000000..7d914a7e --- /dev/null +++ b/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/pages/dashboard/BottomTicker.tsx @@ -0,0 +1,41 @@ +// ©AngelaMos | 2026 +// BottomTicker.tsx + +import { useTicker } from '@/stores/ticker' +import styles from './BottomTicker.module.scss' + +const MS_PER_SECOND = 1000 +const SECONDS_PER_MINUTE = 60 +const SECONDS_PER_HOUR = 3600 + +export function BottomTicker(): React.ReactElement { + const items = useTicker((s) => s.items) + return ( +
+ {items.length > 0 && ( +
+ {items.map((item) => ( + + {item.source} + {item.headline} + {formatRel(item.ts)} + + ))} +
+ )} +
+ ) +} + +BottomTicker.displayName = 'BottomTicker' + +function formatRel(ts: number): string { + const diff = (Date.now() - ts) / MS_PER_SECOND + if (diff < SECONDS_PER_MINUTE) { + return `${Math.floor(diff)}s ago` + } + if (diff < SECONDS_PER_HOUR) { + return `${Math.floor(diff / SECONDS_PER_MINUTE)}m ago` + } + return `${Math.floor(diff / SECONDS_PER_HOUR)}h ago` +} diff --git a/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/pages/dashboard/Dashboard.tsx b/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/pages/dashboard/Dashboard.tsx index 5caec687..5a28da01 100644 --- a/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/pages/dashboard/Dashboard.tsx +++ b/PROJECTS/advanced/monitor-the-situation-dashboard/frontend/src/pages/dashboard/Dashboard.tsx @@ -2,6 +2,7 @@ // Dashboard.tsx import { AlertBanner } from './AlertBanner' +import { BottomTicker } from './BottomTicker' import styles from './Dashboard.module.scss' import { TopStrip } from './TopStrip' @@ -15,6 +16,7 @@ export function Dashboard(): React.ReactElement {