wayfarer-weather/components/SiteFooter.tsx
Cayden Schwechten 6250d23297 init
2026-10-31 21:20:16 -05:00

211 lines
8.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { formatClock } from "@/lib/display";
import { pixelLabel } from "@/lib/styles";
import type { ProviderId, WeatherReport } from "@/lib/weather/types";
const LINK = "text-gold hover:text-gold-bright underline decoration-gold-dim underline-offset-2";
function ProviderCredit({ provider }: { provider: ProviderId }) {
switch (provider) {
case "openweather":
return (
<>
Weather data provided by{" "}
<a href="https://openweathermap.org/" target="_blank" rel="noopener" className={LINK}>
OpenWeather
</a>{" "}
(
<a href="https://creativecommons.org/licenses/by-sa/4.0/" target="_blank" rel="noopener" className={LINK}>
CC BY-SA 4.0
</a>{" "}
/{" "}
<a href="https://opendatacommons.org/licenses/odbl/" target="_blank" rel="noopener" className={LINK}>
ODbL
</a>
)
</>
);
case "openmeteo":
return (
<>
Weather data by{" "}
<a href="https://open-meteo.com/" target="_blank" rel="noopener" className={LINK}>
Open-Meteo.com
</a>{" "}
(
<a href="https://creativecommons.org/licenses/by/4.0/" target="_blank" rel="noopener" className={LINK}>
CC BY 4.0
</a>
)
</>
);
case "weatherapi":
return (
<>
Powered by{" "}
<a href="https://www.weatherapi.com/" title="Free Weather API" target="_blank" rel="noopener" className={LINK}>
WeatherAPI.com
</a>
</>
);
case "tomorrow":
return (
<>
Powered by{" "}
<a href="https://www.tomorrow.io/" target="_blank" rel="noopener" className={LINK}>
Tomorrow.io
</a>
</>
);
}
}
/**
* Visible attribution, safety disclaimer, and privacy disclosure required
* across the weather, geocoding, air-quality, alert, and basemap providers.
*/
export function SiteFooter({
report,
activeProvider,
hasOpenWeather,
}: {
report: WeatherReport | null;
activeProvider: ProviderId;
hasOpenWeather: boolean;
}) {
const creditedProvider = report?.provider ?? activeProvider;
const camsYear = report ? new Date(report.fetchedAt).getUTCFullYear() : null;
return (
<footer className="mt-4 flex flex-col gap-2.5 border-t border-gold-dim/50 pt-4 text-xs leading-relaxed text-stone">
{/* Live visible attribution line for active data on screen */}
<div className="flex flex-wrap items-baseline justify-between gap-x-4 gap-y-1">
<p>
<ProviderCredit provider={creditedProvider} />
{report && <>, updated {formatClock(report.fetchedAt, null)}</>}.
{report?.airQuality && (
<>
{" "}Air quality by{" "}
<a href="https://open-meteo.com/" target="_blank" rel="noopener" className={LINK}>
Open-Meteo.com
</a>{" "}
— contains modified{" "}
<a href="https://atmosphere.copernicus.eu/" target="_blank" rel="noopener" className={LINK}>
Copernicus Atmosphere Monitoring Service (CAMS)
</a>{" "}
information ({camsYear}).
</>
)}
</p>
<p className="text-[11px]">
{hasOpenWeather ? (
<>
Places via{" "}
<a href="https://openweathermap.org/" target="_blank" rel="noopener" className={LINK}>
OpenWeather
</a>
</>
) : (
<>
Location data based on{" "}
<a href="https://www.geonames.org/" target="_blank" rel="noopener" className={LINK}>
GeoNames
</a>{" "}
(
<a href="https://creativecommons.org/licenses/by/4.0/" target="_blank" rel="noopener" className={LINK}>
CC BY 4.0
</a>
)
</>
)}
</p>
</div>
{/* Expandable legal, safety & privacy notice + author signature */}
<div className="flex flex-col gap-2.5">
<div className="flex flex-wrap items-center justify-between gap-x-4 gap-y-2">
<details className="group w-full">
<summary className={`inline-flex cursor-pointer list-none items-center gap-1.5 ${pixelLabel} hover:text-gold-bright`}>
<span className="inline-block transition-transform group-open:rotate-90" aria-hidden="true">
›
</span>
Data licenses, safety disclaimer &amp; privacy
</summary>
<div className="mt-2.5 grid gap-3 border border-gold-dim/50 bg-panel/70 p-4 text-xs leading-relaxed sm:grid-cols-3">
<div className="flex flex-col gap-1">
<p className="font-pixel text-[0.68rem] text-gold-bright">Safety disclaimer</p>
<p>
Weather forecasts, radar imagery, and alert summaries are provided &ldquo;as is&rdquo; without warranty for general
informational use. Do not rely solely on this site for life-safety or emergency decisions; monitor{" "}
<a href="https://www.weather.gov/" target="_blank" rel="noopener" className={LINK}>
weather.gov
</a>{" "}
or your national meteorological service. Not affiliated with or endorsed by NOAA/NWS.
</p>
</div>
<div className="flex flex-col gap-1">
<p className="font-pixel text-[0.68rem] text-gold-bright">Map &amp; radar credits</p>
<p>
Basemap &copy;{" "}
<a href="https://www.openstreetmap.org/copyright" target="_blank" rel="noopener" className={LINK}>
OpenStreetMap
</a>{" "}
contributors, &copy;{" "}
<a href="https://carto.com/attributions" target="_blank" rel="noopener" className={LINK}>
CARTO
</a>
. Global radar by{" "}
<a href="https://www.rainviewer.com/" target="_blank" rel="noopener" className={LINK}>
RainViewer
</a>
; US NEXRAD composite via{" "}
<a href="https://mesonet.agron.iastate.edu/" target="_blank" rel="noopener" className={LINK}>
Iowa Environmental Mesonet
</a>{" "}
(Iowa State University). Raw weather metrics are unit-converted and normalized for display.
</p>
</div>
<div className="flex flex-col gap-1">
<p className="font-pixel text-[0.68rem] text-gold-bright">Privacy</p>
<p>
Wayfarer uses no accounts, ad trackers, or analytics cookies. Unit preferences and recent waypoints stay in your
browser&rsquo;s <code className="font-pixel text-[0.65rem] text-ink">localStorage</code>. Coordinates shared via
&ldquo;Use my location&rdquo; are used only in real time to fetch forecast and map data and are never stored on
our server.
</p>
</div>
</div>
</details>
</div>
<div className="flex flex-wrap items-center justify-between gap-x-4 gap-y-1 border-t border-gold-dim/35 pt-2.5 text-xs">
<p className="flex items-baseline gap-2">
<span className="font-display text-xs font-bold tracking-[0.22em] text-gold uppercase">Wayfarer</span>
<a
href="https://caydens.dev"
target="_blank"
rel="noopener"
className="group/author font-pixel text-[0.68rem] tracking-[0.05em] text-stone transition-colors hover:text-gold-bright"
>
by{" "}
<span className="text-gold underline decoration-gold-dim underline-offset-2 transition-colors group-hover/author:text-gold-bright">
Cayden Codes
</span>
</a>
</p>
<a
href="https://caydens.dev"
target="_blank"
rel="noopener"
className="font-pixel text-[0.68rem] text-stone transition-colors hover:text-gold-bright"
>
caydens.dev ↗
</a>
</div>
</div>
</footer>
);
}