211 lines
8.3 KiB
TypeScript
211 lines
8.3 KiB
TypeScript
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 & 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 “as is” 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 & radar credits</p>
|
||
<p>
|
||
Basemap ©{" "}
|
||
<a href="https://www.openstreetmap.org/copyright" target="_blank" rel="noopener" className={LINK}>
|
||
OpenStreetMap
|
||
</a>{" "}
|
||
contributors, ©{" "}
|
||
<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’s <code className="font-pixel text-[0.65rem] text-ink">localStorage</code>. Coordinates shared via
|
||
“Use my location” 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>
|
||
);
|
||
}
|