diff --git a/package.json b/package.json
index f7d5863..77b3490 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,7 @@
"version": "1.0.0",
"type": "module",
"scripts": {
- "dev": "vite",
+ "dev": "vite --host",
"build": "vite build",
"preview": "vite preview",
"format": "prettier --write --plugin-search-dir . .",
diff --git a/src/App.svelte b/src/App.svelte
index 0d52a01..62bf5d2 100644
--- a/src/App.svelte
+++ b/src/App.svelte
@@ -16,6 +16,7 @@
import HourlyDetails from './components/HourlyDetails.svelte';
import SettingsModal from './SettingsModal.svelte';
import AboutModal from './AboutModal.svelte';
+ import Precipitation from './components/scalars/Precipitation.svelte';
/* Constants */
const navbarButtonClass = 'text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg text-sm p-2.5';
@@ -110,9 +111,10 @@
{#if weather}
-
+ {@const { sunset_timestamp, sunrise_timestamp, precipitation_amount, precipitation_probability } = weather.daily[0]}
+
-
+
- {#each weather.daily as daily}
-
-
- d.temperature_low))}
- global_high={Math.max(...weather.daily.map((d) => d.temperature_high))}
- />
-
-
-
-
+ {#each weather.daily as daily, i}
+ {#if ($configuration.layout === 'vertical' && i) > 0 || $configuration.layout === 'horizontal'}
+
+
+ d.temperature_low))}
+ global_high={Math.max(...weather.daily.map((d) => d.temperature_high))}
+ />
+
+
+
+
+ {/if}
{/each}
{:else if error}
diff --git a/src/Configuration.ts b/src/Configuration.ts
index b80f0d8..d870a49 100644
--- a/src/Configuration.ts
+++ b/src/Configuration.ts
@@ -15,6 +15,7 @@ export interface Configuration {
providerParams: object;
location: Location | undefined;
units: Units;
+ layout: string;
title: string;
refreshInterval: number;
}
@@ -24,6 +25,7 @@ const DEFAULT_CONFIGURATION: Configuration = {
providerParams: {},
location: undefined,
units: new Intl.Locale(window.navigator.language).region === 'US' ? Units.Imperial : Units.Metric,
+ layout: 'horizontal',
title: '',
refreshInterval: 2 * 3600,
};
@@ -32,6 +34,7 @@ export function decodeConfiguration(params: object): Configuration {
const providerFactory = ProviderFactories.find((e) => e.id === params['provider']) || DEFAULT_CONFIGURATION.providerFactory;
const providerParams = Object.fromEntries(providerFactory.fields.map((f: { name: string }) => [f.name, params[f.name] || undefined]));
const location = Location.fromString(params['location']) || DEFAULT_CONFIGURATION.location;
+ const layout = params['layout'] || DEFAULT_CONFIGURATION.layout;
const title = params['title'] || DEFAULT_CONFIGURATION.title;
const units = params['units'] === 'metric' ? Units.Metric : params['units'] === 'imperial' ? Units.Imperial : DEFAULT_CONFIGURATION.units;
const refreshInterval = parseInt(params['refresh_interval']) || DEFAULT_CONFIGURATION.refreshInterval;
@@ -40,6 +43,7 @@ export function decodeConfiguration(params: object): Configuration {
providerFactory,
providerParams,
location,
+ layout,
title,
units,
refreshInterval,
@@ -64,6 +68,9 @@ export function encodeConfiguration(configuration: Configuration): object {
if (configuration.title !== DEFAULT_CONFIGURATION.title) {
params['title'] = configuration.title;
}
+ if (configuration.layout !== DEFAULT_CONFIGURATION.layout) {
+ params['layout'] = configuration.layout;
+ }
if (configuration.refreshInterval !== DEFAULT_CONFIGURATION.refreshInterval) {
params['refresh_interval'] = configuration.refreshInterval;
}
diff --git a/src/SettingsModal.svelte b/src/SettingsModal.svelte
index 0474c5a..0bf6b87 100644
--- a/src/SettingsModal.svelte
+++ b/src/SettingsModal.svelte
@@ -27,6 +27,7 @@
let title: string;
let refreshInterval: number;
let valid: boolean;
+ let layout: string;
/* Loading State for location */
let locationLoading: boolean = false;
@@ -46,6 +47,7 @@
locationMode = currentConfiguration.location ? LocationMode.Coordinates : LocationMode.Geolocation;
location = currentConfiguration.location || new Location('', '');
units = currentConfiguration.units;
+ layout = currentConfiguration.layout;
title = currentConfiguration.title;
refreshInterval = currentConfiguration.refreshInterval;
@@ -80,6 +82,7 @@
providerParams,
location: (providerFactory.requiresLocation && locationMode === LocationMode.Coordinates && location.valid() && location) || undefined,
units,
+ layout,
title,
refreshInterval,
};
@@ -164,6 +167,18 @@
/>
+
diff --git a/src/components/CurrentDetails.svelte b/src/components/CurrentDetails.svelte
index 1278572..0ef269f 100644
--- a/src/components/CurrentDetails.svelte
+++ b/src/components/CurrentDetails.svelte
@@ -1,5 +1,7 @@
-
-
-
+
+
+
Feels Like:
Low:
@@ -23,7 +30,7 @@
-
+
Wind:
Humidity:
Dew Point:
@@ -34,4 +41,6 @@
Visibility:
{/if}
+
+
diff --git a/src/components/DailyDetails.svelte b/src/components/DailyDetails.svelte
index fd9eb5d..49ab8cf 100644
--- a/src/components/DailyDetails.svelte
+++ b/src/components/DailyDetails.svelte
@@ -1,35 +1,22 @@
-
-
-
-
-
-
-
- {#if daily.precipitation_probability !== undefined}
-
- Precipitation: {daily.precipitation_probability}%
-
- {/if}
- {#if daily.precipitation_amount !== undefined}
-
- {/if}
+
+
+
+
+
+
diff --git a/src/components/DailyPrecipitationDetails.svelte b/src/components/DailyPrecipitationDetails.svelte
new file mode 100644
index 0000000..69d4707
--- /dev/null
+++ b/src/components/DailyPrecipitationDetails.svelte
@@ -0,0 +1,24 @@
+
+
+{#if precipitation.precipitation_probability !== undefined && precipitation.precipitation_amount !== undefined}
+
+ Precipitation: {precipitation.precipitation_probability}%
+
+
+{:else if precipitation.precipitation_probability !== undefined}
+
+ Precipitation: {precipitation.precipitation_probability}%
+
+{:else if precipitation.precipitation_amount !== undefined}
+
+{/if}
diff --git a/src/components/DailySunDetails.svelte b/src/components/DailySunDetails.svelte
new file mode 100644
index 0000000..5389559
--- /dev/null
+++ b/src/components/DailySunDetails.svelte
@@ -0,0 +1,18 @@
+
+
+
+
+ Sunrise:
+
+
+
+ Sunset:
+
diff --git a/src/components/HourlyDetails.svelte b/src/components/HourlyDetails.svelte
index 5be2173..dda1b2b 100644
--- a/src/components/HourlyDetails.svelte
+++ b/src/components/HourlyDetails.svelte
@@ -1,6 +1,7 @@
-
- {#each aggregation as entry}
-
- {#if entry.duration > 4}
-
{CLASS_TEXT_MAP[entry.conditions][1]}
- {:else if entry.duration > 2}
-
{CLASS_TEXT_MAP[entry.conditions][1]}
- {/if}
-
- {/each}
-
-
- {#each Array(25) as _, i}
-
- {/each}
-
-
-
-
-
-
+{#if $configuration.layout === 'horizontal'}
+
+ {#each aggregation as entry}
+
+ {#if entry.duration > 4}
+
{CLASS_TEXT_MAP[entry.conditions][1]}
+ {:else if entry.duration > 2}
+
{CLASS_TEXT_MAP[entry.conditions][1]}
+ {/if}
+
+ {/each}
+
+
+ {#each Array(25) as _, i}
+
+ {/each}
- {#each Array(11) as _, i}
- {@const timestamp = hourly[2 * (i + 1)].timestamp}
-
-
-
+
-
-
-
-
+ {#each Array(11) as _, i}
+ {@const timestamp = hourly[2 * (i + 1)].timestamp}
+
+ {/each}
+
+
+
+
+ {#each Array(11) as _, i}
+ {@const temperature = hourly[2 * (i + 1)].temperature}
+
+ {/each}
+
- {#each Array(11) as _, i}
- {@const temperature = hourly[2 * (i + 1)].temperature}
-
-
-
+{:else if $configuration.layout === 'vertical'}
+
+
+ {#each aggregation as entry}
+
+
+ {/each}
+
+
+
+ {#if today}
+ Now
+ {:else}
+
+
+
+ {/if}
+ {hourly[0].conditions}
+
+
+ {#each Array(11) as _, i}
+ {@const timestamp = hourly[2 * (i + 1)].timestamp}
+ {@const condition = hourly[2 * (i + 1)].conditions}
+ {@const previousCondition = hourly[2 * i].conditions}
+ {@const newCondition = previousCondition !== condition}
+
+
+ {newCondition ? condition : ''}
+
+
+
+ {/each}
- {/each}
-
-
+
+ {#each Array(12) as _, i}
+ {@const temperature = hourly[2 * i].temperature}
+ {@const width = (100 * (temperature - temperatureLow)) / (temperatureHigh - temperatureLow)}
+
+
+
+
+
+
+ {/each}
+
+
+{/if}
diff --git a/src/components/scalars/Temperature.svelte b/src/components/scalars/Temperature.svelte
index 9c84d77..52406c0 100644
--- a/src/components/scalars/Temperature.svelte
+++ b/src/components/scalars/Temperature.svelte
@@ -2,14 +2,17 @@
import { configuration, Units } from '../../Configuration';
export let value: number = 0;
+ export let pill: boolean = false;
function cToF(temperature: number): number {
return (temperature * 9) / 5 + 32;
}
+
+ $: pillStyle = pill ? 'border border-slate-300 rounded-full px-2 py-0.5 font-medium' : '';
{#if $configuration.units === Units.Imperial}
-
{cToF(value).toFixed(0)}°
+
{cToF(value).toFixed(0)}°
{:else}
-
{value.toFixed(1)}°
+
{value.toFixed(1)}°
{/if}
diff --git a/src/components/scalars/TemperatureRange.svelte b/src/components/scalars/TemperatureRange.svelte
index 4c223ea..c4b036a 100644
--- a/src/components/scalars/TemperatureRange.svelte
+++ b/src/components/scalars/TemperatureRange.svelte
@@ -19,7 +19,7 @@
-
+
diff --git a/src/providers/Provider.ts b/src/providers/Provider.ts
index db9285c..a5440da 100644
--- a/src/providers/Provider.ts
+++ b/src/providers/Provider.ts
@@ -74,6 +74,15 @@ export interface ProviderFactory {
fromParams(params: object, location?: Location): Provider | null;
}
+export interface SunTimes {
+ sunrise_timestamp: Date;
+ sunset_timestamp: Date;
+}
+export interface DailyPrecipitation {
+ precipitation_probability?: number; // in integral percent 0-100
+ precipitation_amount?: number; // in mm
+}
+
export interface Provider {
fetch(): Promise
;
}