init
This commit is contained in:
commit
6250d23297
53 changed files with 6381 additions and 0 deletions
49
components/AlertsBanner.tsx
Normal file
49
components/AlertsBanner.tsx
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import { formatClock, formatShortDate } from "@/lib/display";
|
||||
import { pixelLabel } from "@/lib/styles";
|
||||
import type { AlertSeverity, WeatherAlert } from "@/lib/weather/types";
|
||||
import { Slot } from "./Slot";
|
||||
|
||||
const SEVERITY_TEXT: Record<AlertSeverity, string> = {
|
||||
extreme: "text-heart",
|
||||
severe: "text-heart",
|
||||
moderate: "text-gold-bright",
|
||||
minor: "text-ink",
|
||||
unknown: "text-ink",
|
||||
};
|
||||
|
||||
/** Active weather alerts. Each one opens to show the full text and instructions. */
|
||||
export function AlertsBanner({ alerts, source, timeZone }: { alerts: WeatherAlert[]; source: string | null; timeZone: string | null }) {
|
||||
if (alerts.length === 0) return null;
|
||||
|
||||
const when = (iso: string | null) => (iso ? `${formatShortDate(iso, timeZone)}, ${formatClock(iso, timeZone)}` : null);
|
||||
|
||||
return (
|
||||
<Slot as="section" tone="danger" innerClassName="flex flex-col gap-2 p-4 sm:px-5">
|
||||
<h2 className="font-display font-bold text-heart">
|
||||
{alerts.length === 1 ? "1 active alert" : `${alerts.length} active alerts`}
|
||||
</h2>
|
||||
|
||||
{alerts.map((alert, i) => (
|
||||
<details key={`${alert.title}-${alert.starts ?? i}`} className="group border-t border-heart-empty pt-2">
|
||||
<summary className={`cursor-pointer list-none font-medium ${SEVERITY_TEXT[alert.severity]}`}>
|
||||
<span className="mr-2 inline-block transition-transform group-open:rotate-90" aria-hidden="true">›</span>
|
||||
{alert.title}
|
||||
</summary>
|
||||
<div className="mt-2 flex flex-col gap-2 pl-4 text-sm">
|
||||
<p className={pixelLabel}>
|
||||
{[alert.source, when(alert.starts) && `from ${when(alert.starts)}`, when(alert.ends) && `until ${when(alert.ends)}`]
|
||||
.filter(Boolean)
|
||||
.join(" · ")}
|
||||
</p>
|
||||
<p className="whitespace-pre-line">{alert.description}</p>
|
||||
{alert.instruction && <p className="whitespace-pre-line text-gold-bright">{alert.instruction}</p>}
|
||||
</div>
|
||||
</details>
|
||||
))}
|
||||
|
||||
<p className={pixelLabel}>
|
||||
{source ? `Alerts from ${source} · ` : ""}Follow official local emergency guidance for life-safety decisions.
|
||||
</p>
|
||||
</Slot>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue