| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- import { createSignal, onMount, onCleanup, Show } from "solid-js";
- import type { WidgetSettings, WidgetSchema } from "../types/widget";
- import { getRefreshInterval } from "../utils/timeUtils";
- interface WeatherProps {
- settings: WidgetSettings;
- }
- interface WeatherData {
- temp: number;
- description: string;
- humidity: number;
- windSpeed: number;
- }
- export function Weather(props: WeatherProps) {
- const [weather, setWeather] = createSignal<WeatherData | null>(null);
- const [error, setError] = createSignal<string>("");
- const fetchWeather = async () => {
- try {
- const city = (props.settings.city as string) || "London";
- const lat = (props.settings.lat as string) || "";
- const lon = (props.settings.lon as string) || "";
- const apiKey = (props.settings.apiKey as string) || "";
- const units = (props.settings.units as string) || "metric";
- if (!apiKey) {
- setError("API key required");
- return;
- }
- // Build URL based on whether lat/lon or city is provided
- let url = `/api/weather?apiKey=${encodeURIComponent(apiKey)}&units=${units}`;
- if (lat && lon) {
- url += `&lat=${encodeURIComponent(lat)}&lon=${encodeURIComponent(lon)}`;
- } else {
- url += `&city=${encodeURIComponent(city)}`;
- }
- // Use our server endpoint instead of calling OpenWeatherMap directly
- const response = await fetch(url);
- if (!response.ok) {
- throw new Error("Failed to fetch weather");
- }
- const data = await response.json();
- setWeather({
- temp: Math.round(data.main.temp),
- description: data.weather[0].description,
- humidity: data.main.humidity,
- windSpeed: data.wind.speed,
- });
- setError("");
- } catch (err) {
- setError("Error fetching weather");
- console.error(err);
- }
- };
- onMount(() => {
- fetchWeather();
- const refreshInterval = getRefreshInterval(props.settings, 10, "minutes");
- const interval = setInterval(fetchWeather, refreshInterval);
- onCleanup(() => clearInterval(interval));
- });
- return (
- <div
- style={{
- border: "1px solid var(--border)",
- padding: "1rem",
- width: "100%",
- height: "100%",
- "box-sizing": "border-box",
- display: "flex",
- "flex-direction": "column",
- "justify-content": "center",
- "align-items": "center",
- background: "var(--bg, #fff)",
- }}
- >
- <Show when={error()}>
- <div
- style={{
- color: "#ff4444",
- "font-size": "clamp(0.7rem, 2vw + 0.5vh, 1rem)",
- "text-align": "center",
- }}
- >
- {error()}
- </div>
- </Show>
- <Show when={!error() && weather()}>
- <div
- style={{
- "font-size": "clamp(0.7rem, 2vw + 0.5vh, 1.2rem)",
- "font-weight": "bold",
- "margin-bottom": "0.5rem",
- "text-align": "center",
- }}
- >
- {props.settings.lat && props.settings.lon
- ? `${props.settings.lat}, ${props.settings.lon}`
- : props.settings.city || "London"}
- </div>
- <div
- style={{
- "font-size": "clamp(1.5rem, 5vw + 1vh, 3.5rem)",
- "font-weight": "bold",
- "text-align": "center",
- "line-height": "1.1",
- }}
- >
- {weather()?.temp}°
- {(props.settings.units as string) === "metric" ? "C" : "F"}
- </div>
- <div
- style={{
- "font-size": "clamp(0.7rem, 1.8vw + 0.5vh, 1.1rem)",
- "text-align": "center",
- "margin-top": "0.3rem",
- "text-transform": "capitalize",
- color: "var(--gray)",
- }}
- >
- {weather()?.description}
- </div>
- <Show when={props.settings.showDetails}>
- <div
- style={{
- display: "flex",
- gap: "1rem",
- "margin-top": "0.8rem",
- "font-size": "clamp(0.6rem, 1.5vw + 0.5vh, 0.9rem)",
- color: "var(--gray)",
- }}
- >
- <div>💧 {weather()?.humidity}%</div>
- <div>💨 {weather()?.windSpeed} m/s</div>
- </div>
- </Show>
- </Show>
- </div>
- );
- }
- export const weatherSchema: WidgetSchema = {
- name: "Weather",
- description: "Display current weather from OpenWeatherMap API",
- settingsSchema: {
- city: {
- type: "string",
- label: "City Name",
- default: "London",
- required: false,
- },
- lat: {
- type: "string",
- label: "Latitude (optional, overrides city)",
- default: "",
- required: false,
- },
- lon: {
- type: "string",
- label: "Longitude (optional, overrides city)",
- default: "",
- required: false,
- },
- apiKey: {
- type: "string",
- label: "OpenWeatherMap API Key",
- default: "",
- required: true,
- },
- units: {
- type: "select",
- label: "Temperature Units",
- default: "metric",
- options: ["metric", "imperial"],
- },
- showDetails: {
- type: "boolean",
- label: "Show Humidity & Wind",
- default: true,
- },
- refreshIntervalValue: {
- type: "number",
- label: "Refresh Interval",
- default: 10,
- required: true,
- },
- refreshIntervalUnit: {
- type: "select",
- label: "Unit",
- options: ["seconds", "minutes", "hours", "days"],
- default: "minutes",
- required: true,
- },
- },
- };
|