A responsive, iOS-Weather-style weather tile for MindooDB Haven. It renders a beautiful forecast for one or more locations configured through a Haven app parameter, and uses the free, keyless Open-Meteo APIs for all data.
The goal of this project is to show how a third-party Haven app can
look and feel like a first-class native tile while staying entirely
client-side. It complements mindoodb-app-example
which focuses on the SDK's database and view APIs; this app
concentrates on the UX side of the SDK: launch parameters,
viewport events, and responsive embedding.
- Reads a list of human-readable locations from the
locationslaunch parameter (e.g.Berlin, Germany;Karlsruhe, Germany;Washington, USA). - Resolves each entry via Open-Meteo's geocoding API and caches the
result in
localStorage. - Fetches a 10-day forecast plus hourly data, current conditions, and air quality for every resolved location.
- Presents each location as a swipeable glass card over a full-bleed photographic background that matches the condition (clear / partly-cloudy / cloudy / rain / snow / storm, day or night).
- Adapts to the tile size Haven reports via
onViewportChange: narrow → single card with dots, wider → 2–4 cards at a time.
| Name | Required | Default | Format & meaning |
|---|---|---|---|
locations |
no | "New York City, USA;Berlin, Deutschland;Singapur, Singapur" |
Semicolon-separated list of free-form queries: "Berlin, Deutschland;Karlsruhe, Deutschland;Washington, USA". Entries are trimmed and de-duplicated. When omitted or empty, the app falls back to that three-city default so the tile is immediately useful with zero configuration. Note: Open-Meteo's geocoder expects country names in their native language (e.g. Deutschland, not Germany; USA or United States). |
units |
no | metric |
metric → °C / km/h / mm / hPa / km. imperial → °F / mph / in / inHg / miles. |
refreshIntervalMinutes |
no | 0 |
Integer minutes between automatic refreshes. 0 disables background refresh. Maximum 1440. |
Parameters are parsed in src/services/launchParams.ts.
Unknown keys are ignored.
- Open a Haven workspace and drop a Weather tile into a space.
- Set the tile's URL to a running instance of this app (see below for dev / Cloudflare Pages options).
- Optionally override
locations(semicolon-separated) and any of the other parameters in the tile's app parameters — with no parameters at all the tile will show forecasts for New York City, Berlin, and Singapur out of the box. - Reload the tile; the first location card appears as soon as the geocoder returns, then the full forecast is fetched in the background.
npm install
npm run devThe dev server listens on http://localhost:4205. You can preview the app outside Haven by passing parameters as URL query strings, for example:
http://localhost:4205/?locations=Berlin%2C%20Germany%3BKarlsruhe%2C%20Germany&units=metric
If you're iterating on the Haven app SDK in the same workspace, use
the :local variants to alias the sources instead of the published
package:
npm run dev:local # aliases ../mindoodb-app-sdk/src
npm run build:local # ditto, for a production buildDeploying the bundle to Cloudflare Pages
mirrors the workflow used by mindoodb-app-example:
npm run build
npm run deploy # builds + wrangler deploy
npm run preview # local Pages preview of the built assetsThe wrangler.jsonc config treats ./dist as
the asset directory and serves it as a single-page application.
- Forecast: https://api.open-meteo.com/v1/forecast
- Geocoding: https://geocoding-api.open-meteo.com/v1/search
- Air quality: https://air-quality-api.open-meteo.com/v1/air-quality
All three endpoints are key-less and CORS-friendly, which makes them ideal for a sandboxed iframe in Haven: no secrets ever need to leave the tile's bundle.
Please respect Open-Meteo's terms of use if you redistribute or deploy the app publicly.
The app deliberately uses a single visual treatment (always-light
text over a photographic background), regardless of Haven's
light/dark theme setting — matching iOS Weather's behaviour. The
SDK's onThemeChange hook is still subscribed for platform
consistency, but its value is not applied to the UI. The background
image (tied to the active card's visual state and day/night) is the
sole "theme" driver.
src/
├── main.ts # createApp, i18n install, mount
├── App.vue # shell: background + carousel
├── app/ # composables: SDK session, orchestrator
├── features/
│ ├── carousel/ # Swiper wrapper + pagination
│ ├── card/ # LocationCard + sub-components
│ │ └── info/ # InfoGrid + info tiles
│ ├── error/ # ErrorCard placeholder tile
│ └── background/ # Full-bleed crossfading bg
├── services/ # geocoding.ts, openMeteo.ts, airQuality.ts, cache.ts, launchParams.ts
├── domain/ # WMO mapping, formatters, time helpers, UV/AQI/wind/pressure bands
├── i18n/ # vue-i18n setup + en/de bundles
├── shared/ # GlassCard, WeatherIcon, LoadingDots, styles
└── tests/ # Vitest unit tests
- More languages: drop a new file next to
src/i18n/en.tsand add it tosrc/i18n/index.ts. - More visual states: bump the mapping in
src/domain/weatherCode.tsand add new background images underpublic/backgrounds/using the naming convention<state>-<day|night>.jpg. - Different icon set: swap the inline SVGs in
src/shared/components/WeatherIcon.vuefor an icon font like Meteocons. - Additional metrics: add more parameters to the Open-Meteo query
in
src/services/openMeteo.tsand render them as new info tiles undersrc/features/card/info/.
npm test # runs Vitest once
npm run test:watch # watch modeTests cover launch-parameter parsing, WMO → visual-state mapping, UV / AQI band classification, wind direction rounding, pressure trend detection, and the localStorage cache layer.