Skip to content

Commit

Permalink
Create vertical layout
Browse files Browse the repository at this point in the history
  • Loading branch information
mhkeller committed Apr 15, 2023
1 parent 0d1369f commit 899cf36
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 74 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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 . .",
Expand Down
33 changes: 18 additions & 15 deletions src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -110,29 +110,32 @@

<div class="container mx-auto">
{#if weather}
<CurrentDetails current={weather.current} />
{@const { sunset_timestamp, sunrise_timestamp } = weather.daily[0]}
<CurrentDetails current={weather.current} suntimes={{ sunset_timestamp, sunrise_timestamp }} />
<div class="mx-6 mb-6">
<HourlyDetails hourly={weather.current.hourly} />
<HourlyDetails hourly={weather.current.hourly} today />
</div>
<Accordion
multiple
activeClasses="bg-gray-100 dark:bg-gray-700 focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-800"
inactiveClasses="hover:bg-gray-100 hover:dark:bg-gray-700"
defaultClass="mx-2 sm:mx-0"
>
{#each weather.daily as daily}
<AccordionItem class="!p-2 md:!p-4">
<span slot="header" class="w-full">
<DailySummary
current={weather.current}
{daily}
global_low={Math.min(...weather.daily.map((d) => d.temperature_low))}
global_high={Math.max(...weather.daily.map((d) => d.temperature_high))}
/>
</span>
<DailyDetails {daily} />
<HourlyDetails hourly={daily.hourly} />
</AccordionItem>
{#each weather.daily as daily, i}
{#if ($configuration.layout === 'vertical' && i) > 0 || $configuration.layout === 'horizontal'}
<AccordionItem class="!p-2 md:!p-4">
<span slot="header" class="w-full">
<DailySummary
current={weather.current}
{daily}
global_low={Math.min(...weather.daily.map((d) => d.temperature_low))}
global_high={Math.max(...weather.daily.map((d) => d.temperature_high))}
/>
</span>
<DailyDetails {daily} />
<HourlyDetails hourly={daily.hourly} />
</AccordionItem>
{/if}
{/each}
</Accordion>
{:else if error}
Expand Down
2 changes: 1 addition & 1 deletion src/SettingsModal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@
id="select-layout"
items={[
{ name: 'Horizontal', value: 'horizontal' },
{ name: 'Vertical', value: 'vertial' },
{ name: 'Vertical', value: 'vertical' },
]}
bind:value={layout}
/>
Expand Down
17 changes: 15 additions & 2 deletions src/components/CurrentDetails.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<script lang="ts">
import type { CurrentWeather } from '../providers/Provider';
import Icon from '@iconify/svelte';
import type { CurrentWeather, SunTimes } from '../providers/Provider';
import Conditions from './scalars/Conditions.svelte';
import ConditionsIcon from './scalars/ConditionsIcon.svelte';
Expand All @@ -9,8 +11,10 @@
import UVIndex from './scalars/UVIndex.svelte';
import Distance from './scalars/Distance.svelte';
import Pressure from './scalars/Pressure.svelte';
import Timestamp from './scalars/Timestamp.svelte';
export let current: CurrentWeather;
export let suntimes: SunTimes;
</script>

<div class="grid grid-rows-2 grid-flow-col justify-center items-center mt-2 mb-4">
Expand All @@ -23,7 +27,7 @@
</div>
</div>

<div class="grid grid-cols-2 md:grid-cols-none md:grid-flow-col place-items-center md:justify-center gap-2 md:gap-8 md:mx-0 mb-6">
<div class="grid grid-cols-2 md:grid-cols-none md:grid-flow-col md:place-items-center md:justify-center gap-2 md:gap-8 md:mx-0 mx-6 mb-6">
<div><span class="font-semibold">Wind: </span><Wind speed={current.wind_speed} direction={current.wind_direction} /></div>
<div><span class="font-semibold">Humidity: </span><RelativeHumidity value={current.relative_humidity} /></div>
<div><span class="font-semibold">Dew Point: </span><Temperature value={current.dew_point_temperature} /></div>
Expand All @@ -34,4 +38,13 @@
<div><span class="font-semibold">Visibility: </span><Distance value={current.visibility} /></div>
{/if}
<div><span class="font-semibold">Pressure: </span><Pressure value={current.pressure} /></div>
<div>
<span class="inline-block" style="transform:translate(-2px,-2px)"><Icon icon="mingcute:sunrise-line" class="inline text-2xl sm:text-3xl align-bottom" /></span>
<span class="font-semibold">Sunrise: </span><Timestamp format="short" value={suntimes.sunrise_timestamp} />
</div>
<div>
<span class="inline-block" style="transform:translate(-2px,-2px)"><Icon icon="mingcute:sunset-fill" class="inline text-2xl sm:text-3xl align-bottom" /></span>
<span class="font-semibold">Sunset: </span><Timestamp format="short" value={suntimes.sunset_timestamp} />
</div>

</div>
34 changes: 22 additions & 12 deletions src/components/DailyDetails.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,32 @@
<div><span class="text-lg sm:text-xl"><Conditions value={daily.conditions} /></span></div>
</div>

<div class="grid grid-flow-col place-items-center md:auto-cols-fr gap-4 md:gap-8 mb-6">
<div>
<Icon icon="mingcute:sunrise-line" class="inline text-2xl sm:text-3xl align-bottom" />
<span class="text-sm md:text-base"><Timestamp format="short" value={daily.sunrise_timestamp} /></span>
<Icon icon="mingcute:sunset-fill" class="inline text-2xl sm:text-3xl align-bottom" />
<span class="text-sm md:text-base"><Timestamp format="short" value={daily.sunset_timestamp} /></span>
</div>
{#if daily.precipitation_probability !== undefined}
<div class="grid grid-cols-2 md:grid-cols-none md:grid-flow-col md:place-items-center md:justify-center gap-2 md:gap-8 ">
{#if daily.precipitation_probability !== undefined && daily.precipitation_amount !== undefined}
<div>
<span class="text-sm md:text-base font-semibold">Precipitation:</span> <span class="text-sm md:text-base">{daily.precipitation_probability}%</span>
</div>
{/if}
{#if daily.precipitation_amount !== undefined}
<div>
<span class="text-sm md:text-base font-semibold">Precipitation:</span>
<span class="text-sm md:text-base"><Amount value={daily.precipitation_amount} /></span>
<span class="text-sm md:text-base font-semibold">Amount:</span> <Amount value={daily.precipitation_amount} />
</div>
{:else if daily.precipitation_probability !== undefined}
<div>
<span class="text-sm md:text-base font-semibold">Precipitation:</span> <span class="text-sm md:text-base">{daily.precipitation_probability}%</span>
</div>
{:else if daily.precipitation_amount !== undefined}
<div>
<span class="text-sm md:text-base font-semibold">Precipitation:</span> <span class="text-sm md:text-base"><Amount value={daily.precipitation_amount} /></span>
</div>
{/if}
</div>

<div class="grid grid-cols-2 md:grid-cols-none md:grid-flow-col md:place-items-center md:justify-center gap-2 md:gap-8 md:mx-0 mt-3 mb-6">
<div>
<span class="inline-block" style="transform:translate(-2px,-2px)"><Icon icon="mingcute:sunrise-line" class="inline text-2xl sm:text-3xl align-bottom" /></span>
<span class="font-semibold">Sunrise: </span><Timestamp format="short" value={daily.sunrise_timestamp} />
</div>
<div>
<span class="inline-block" style="transform:translate(-2px,-2px)"><Icon icon="mingcute:sunset-fill" class="inline text-2xl sm:text-3xl align-bottom" /></span>
<span class="font-semibold">Sunset: </span><Timestamp format="short" value={daily.sunset_timestamp} />
</div>
</div>
135 changes: 94 additions & 41 deletions src/components/HourlyDetails.svelte
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
<script lang="ts">
import { ConditionsIcon } from '../providers/Provider';
import type { HourlyWeather } from '../providers/Provider';
import { configuration } from '../Configuration';
import Temperature from './scalars/Temperature.svelte';
import Timestamp from './scalars/Timestamp.svelte';
/* Properties */
export let hourly: HourlyWeather[] = [];
export let today: boolean = false;
/* Constants */
Expand Down Expand Up @@ -79,6 +81,8 @@
return opacity.toFixed(2);
}
$: {
/* Aggregate conditions into contiguous regions */
aggregation = [];
Expand All @@ -97,51 +101,100 @@
}
</script>

<div class="flex mb-1.5 overflow-hidden rounded-md text-sm sm:text-base">
{#each aggregation as entry}
<div class="h-10 leading-9 {CLASS_TEXT_MAP[entry.conditions][0]} text-center" style="width: {(100 * entry.duration) / 24}%;">
{#if entry.duration > 4}
<div class="truncate">{CLASS_TEXT_MAP[entry.conditions][1]}</div>
{:else if entry.duration > 2}
<div class="hidden md:block truncate">{CLASS_TEXT_MAP[entry.conditions][1]}</div>
{/if}
</div>
{/each}
</div>
<div class="flex w-full mb-1">
{#each Array(25) as _, i}
<div class="{i % 2 === 0 ? 'h-[8px]' : 'h-[5px]'} border-l border-gray-400" style="width: {i < 24 ? 100 / 24 : 0}%;" />
{/each}
</div>
<div class="flex w-full text-xs sm:text-sm">
<div style="width: {100 / 24}%;">
<div class="hidden md:block">
<Timestamp value={hourly[0].timestamp} format="hour" />
</div>
{#if $configuration.layout === 'horizontal'}
<div class="flex mb-1.5 overflow-hidden rounded-md text-sm sm:text-base">
{#each aggregation as entry}
<div class="h-10 leading-9 {CLASS_TEXT_MAP[entry.conditions][0]} text-center" style="width: {(100 * entry.duration) / 24}%;">
{#if entry.duration > 4}
<div class="truncate">{CLASS_TEXT_MAP[entry.conditions][1]}</div>
{:else if entry.duration > 2}
<div class="hidden md:block truncate">{CLASS_TEXT_MAP[entry.conditions][1]}</div>
{/if}
</div>
{/each}
</div>
<div class="flex w-full mb-1">
{#each Array(25) as _, i}
<div class="{i % 2 === 0 ? 'h-[8px]' : 'h-[5px]'} border-l border-gray-400" style="width: {i < 24 ? 100 / 24 : 0}%;" />
{/each}
</div>
{#each Array(11) as _, i}
{@const timestamp = hourly[2 * (i + 1)].timestamp}
<div class="text-center" style="width: {100 / 12}%;">
<div class="{i === 0 || i === 2 || i === 4 || i === 6 || i === 8 || i === 10 ? 'block' : 'hidden'} md:block">
<Timestamp value={timestamp} format="hour" />
<div class="flex w-full text-xs sm:text-sm">
<div style="width: {100 / 24}%;">
<div class="hidden md:block">
<Timestamp value={hourly[0].timestamp} format="hour" />
</div>
</div>
{/each}
<div style="width: {100 / 24}%;" />
</div>
<div class="flex w-full mb-2 text-base sm:text-lg font-light text-black dark:text-white">
<div style="width: {100 / 24}%; opacity: {temperatureOpacity(hourly[0].temperature)};">
<div class="hidden md:block">
<Temperature value={hourly[0].temperature} />
{#each Array(11) as _, i}
{@const timestamp = hourly[2 * (i + 1)].timestamp}
<div class="text-center" style="width: {100 / 12}%;">
<div class="{i === 0 || i === 2 || i === 4 || i === 6 || i === 8 || i === 10 ? 'block' : 'hidden'} md:block">
<Timestamp value={timestamp} format="hour" />
</div>
</div>
{/each}
<div style="width: {100 / 24}%;" />
</div>
<div class="flex w-full mb-2 text-base sm:text-lg font-light text-black dark:text-white">
<div style="width: {100 / 24}%; opacity: {temperatureOpacity(hourly[0].temperature)};">
<div class="hidden md:block">
<Temperature value={hourly[0].temperature} />
</div>
</div>
{#each Array(11) as _, i}
{@const temperature = hourly[2 * (i + 1)].temperature}
<div class="text-center" style="width: {100 / 12}%; opacity: {temperatureOpacity(temperature)};">
<div class="{i === 0 || i === 2 || i === 4 || i === 6 || i === 8 || i === 10 ? 'block' : 'hidden'} md:block">
&nbsp;<Temperature value={temperature} />
</div>
</div>
{/each}
<div style="width: {100 / 24}%;" />
</div>
{#each Array(11) as _, i}
{@const temperature = hourly[2 * (i + 1)].temperature}
<div class="text-center" style="width: {100 / 12}%; opacity: {temperatureOpacity(temperature)};">
<div class="{i === 0 || i === 2 || i === 4 || i === 6 || i === 8 || i === 10 ? 'block' : 'hidden'} md:block">
&nbsp;<Temperature value={temperature} />
{:else if $configuration.layout === 'vertical'}
<div class="flex flex-row mx-auto">
<div class="flex flex-col w-7 overflow-hidden rounded-md text-sm sm:text-base">
{#each aggregation as entry}
<div class="{CLASS_TEXT_MAP[entry.conditions][0]}" style="height: {100 * entry.duration / 24}%;">
</div>
{/each}
</div>
<div class="text-sm ml-2">
<div style="height:{100 / 24}%;transform:translateY(-4px);" class="grow flex items-top">
{#if today}
<span class="font-bold w-9 mr-2 inline-block text-right">Now</span>
{:else}
<span class="font-bold w-9 mr-2 inline-block text-right">
<Timestamp value={hourly[0].timestamp} format="hour" />
</span>
{/if}
<span class="font-normal italic mr-2">{hourly[0].conditions}</span>
<span class="min-w-fit inline-block border-solid border-b-[1px] border-slate-300 grow h-2/4"></span>
</div>
<div style="height:{100 / 24}%;transform:translateY(-4px);">&nbsp;</div>
{#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}
<div style="height:{100 / 24}%;transform:translateY(-4px);" class="font-bold grow flex items-top">
<span class="w-9 mr-2 inline-block text-right"><Timestamp value={timestamp} format="hour" /></span>
<span class="font-normal italic mr-2 {newCondition ? 'block' : 'hidden'}">{newCondition ? condition : ''}</span>
<span class="min-w-fit inline-block border-solid border-b-[1px] border-slate-300 grow h-2/4"></span>
</div>
<div style="height:{100 / 24}%;background:transparent;">&nbsp;</div>
{/each}
</div>
{/each}
<div style="width: {100 / 24}%;" />
</div>
<div class="grow text-base sm:text-lg font-light text-black dark:text-white" >
{#each Array(12) as _, i}
{@const temperature = hourly[2 * i].temperature}
{@const width = (100 * (temperature - temperatureLow)) / (temperatureHigh - temperatureLow)}

<div style="height:{100 / 24}%;transform:translateY(-4px);" class="grow flex items-top">
<span class="min-w-fit inline-block border-solid border-b-[1px] border-slate-300 h-2/4" style="min-width: calc({width}% - 50px);"></span>
<span class="ml-2" style="transform:translateY(-1px);"><Temperature pill value={temperature} /></span>
</div>
<div style="height:{100 / 24}%;">&nbsp;</div>
{/each}
</div>
</div>
{/if}
7 changes: 5 additions & 2 deletions src/components/scalars/Temperature.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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' : '';
</script>

{#if $configuration.units === Units.Imperial}
<span>{cToF(value).toFixed(0)}°</span>
<span class={pillStyle}>{cToF(value).toFixed(0)}°</span>
{:else}
<span>{value.toFixed(1)}°</span>
<span class={pillStyle}>{value.toFixed(1)}°</span>
{/if}
5 changes: 5 additions & 0 deletions src/providers/Provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ export interface ProviderFactory {
fromParams(params: object, location?: Location): Provider | null;
}

export interface SunTimes {
sunrise_timestamp: Date;
sunset_timestamp: Date;
}

export interface Provider {
fetch(): Promise<Weather>;
}

0 comments on commit 899cf36

Please sign in to comment.