Skip to content

Commit

Permalink
improve list ui
Browse files Browse the repository at this point in the history
  • Loading branch information
jonerrr committed Jul 9, 2024
1 parent cb97c21 commit e790ba9
Show file tree
Hide file tree
Showing 9 changed files with 161 additions and 71 deletions.
5 changes: 4 additions & 1 deletion frontend/src/lib/components/ContentList.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
});
</script>

<div bind:this={list_el} class="flex flex-col overflow-auto max-h-96 px-2">
<div
bind:this={list_el}
class="flex flex-col divide-y divide-neutral-500 overflow-auto max-h-96 px-2"
>
<slot />
</div>
70 changes: 62 additions & 8 deletions frontend/src/lib/components/List.svelte
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
<script lang="ts">
import { persisted } from 'svelte-persisted-store';
import { onDestroy, onMount } from 'svelte';
import { BusFront, TrainFront } from 'lucide-svelte';
import { createTabs, melt } from '@melt-ui/svelte';
// import { item_heights } from '$lib/stores';
// import { derived } from 'svelte/store';
// manage the min/max height of the list
export let manage_height: boolean = true;
export let title: string = 'List';
export const tab_value = persisted(`${title.toLowerCase()}_tab`, 'Train');
const {
elements: { root, list, content, trigger },
states: { value }
} = createTabs({
defaultValue: 'Train',
value: tab_value
});
let list_el: HTMLDivElement;
export function scrollIntoView() {
list_el.scrollIntoView({ behavior: 'smooth' });
}
// manage the min/max height of the list
export let manage_height: boolean = true;
let list_height = 0;
let interval: number;
Expand All @@ -21,8 +32,8 @@
if (list_el == null) return;
const els = Array.from(list_el.querySelectorAll('#list-item')).slice(0, 3);
list_height = els.reduce((h, e) => e.clientHeight + h, 0);
list_height += 10;
list_height = els.reduce((h, e) => e.offsetHeight + h, 0);
// list_height += 10;
}, 100);
});
Expand All @@ -33,9 +44,52 @@
</script>

<div
use:melt={$root}
bind:this={list_el}
style={manage_height ? `min-height: ${list_height}px; max-height: ${list_height}px;` : ''}
class={`relative flex flex-col text-indigo-200 bg-neutral-800/90 border border-neutral-700 p-1 overflow-auto ${$$props.class} ?? ''}`}
>
<slot />
<div id="list-item" class="flex pb-1 justify-between">
<div class="font-bold text-lg text-indigo-300 flex gap-1">
{title}
<!-- for geolocate -->
<slot name="title" />
</div>

<div
use:melt={$list}
class="grid grid-cols-2 bg-neutral-900 rounded shrink-0 overflow-x-auto text-indigo-100 border border-neutral-500"
aria-label="List"
>
<button
use:melt={$trigger('Train')}
class="trigger p-1 px-2 rounded-l relative border-neutral-400 border-r data-[state=active]:bg-indigo-800"
>
<TrainFront />
</button>
<button
use:melt={$trigger('Bus')}
class="trigger p-1 px-2 rounded-r relative border-neutral-400 border-l data-[state=active]:bg-indigo-800"
>
<BusFront />
</button>
</div>
</div>

{#if $value === 'Train'}
<div use:melt={$content('Train')}>
<slot />
</div>
{:else if $value === 'Bus'}
<div use:melt={$content('Bus')}>
<slot name="bus" />
</div>
{/if}
<!-- TODO: Figure out why list height is wrong when using these -->
<!-- <div use:melt={$content('Train')}>
<slot />
</div>
<div use:melt={$content('Bus')}>
<slot name="bus" />
</div> -->
</div>
2 changes: 1 addition & 1 deletion frontend/src/lib/components/Stop/Content.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
</div>
{/if}

<div use:melt={$root} class="flex flex-col shadow-2xl text-indigo-400 bg-neutral-900/70">
<div use:melt={$root} class="flex flex-col shadow-2xl text-indigo-400 bg-neutral-900/80">
<div
use:melt={$list}
class="flex shrink-0 overflow-x-auto text-indigo-100"
Expand Down
108 changes: 61 additions & 47 deletions frontend/src/lib/components/Stop/List.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -135,18 +135,20 @@
});
</script>

<List bind:manage_height bind:this={list_el}>
<div use:melt={$root} class="flex border border-neutral-800 flex-col rounded-xl shadow-lg">
<List bind:manage_height bind:this={list_el} bind:title>
<div slot="title">
{#if show_location}
<slot name="location" />
{/if}
</div>

<!-- <div use:melt={$root} class="flex border border-neutral-800 flex-col rounded-xl shadow-lg">
<div id="list-item" class="flex pb-1 justify-between">
<div class="flex gap-2">
<div class="font-semibold text-lg text-indigo-300">{title}</div>
</div> -->

{#if show_location}
<slot name="location" />
{/if}
</div>

<div
<!-- <div
use:melt={$list}
class="grid grid-cols-2 bg-neutral-900 rounded shrink-0 overflow-x-auto text-indigo-100 border border-neutral-500"
aria-label="List"
Expand All @@ -164,48 +166,60 @@
<BusFront />
</button>
</div>
</div>
<!-- TODO: use melt $content instead of if statement -->
<div
class={`flex flex-col gap-1 ${show_search ? 'max-h-[calc(100dvh-13rem)] overflow-auto' : 'max-h-[calc(100dvh-4rem)]'}`}
>
{#if $value === 'Train'}
{#if $stops}
<!-- TODO: figure out a way to make list length only 3 rows long (maybe get innerheight from trigger component and put in writable) -->
{#each $stops as stop (stop?.id)}
<Trigger {stop} />
{/each}
{/if}
{:else if $value === 'Bus'}
{#if $bus_stops}
{#each $bus_stops as stop (stop?.id)}
<BusTrigger {stop} />
{/each}
{/if}
</div> -->
<!-- <div
class={`flex flex-col gap-1 ${show_search ? 'max-h-[calc(100dvh-13rem)] overflow-auto' : 'max-h-[calc(100dvh-4rem)]'}`}
>
{#if $value === 'Train'}
{#if $stops}
{#each $stops as stop (stop?.id)}
<Trigger {stop} />
{/each}
{/if}
{:else if $value === 'Bus'}
{#if $bus_stops}
{#each $bus_stops as stop (stop?.id)}
<BusTrigger {stop} />
{/each}
{/if}
</div>

<!-- TODO: prevent virtual keyboard from blocking results (use window.visualViewport.height to calculate max height of stops list or virtual keyboard api whenever that comes out) -->
{#if show_search && search === 'ready'}
<div class="relative">
<input
bind:this={search_el}
bind:value={search_term}
on:input={debounce(searchStops)}
type="search"
placeholder="Search stops"
class="search-stops text-indigo-200 max-w-[calc(100vw-10px)] pl-10 z-20 w-full h-12 rounded bg-neutral-900 shadow-2xl border-neutral-800/20 ring-1 ring-inset ring-neutral-700 placeholder:text-neutral-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600"
/>
<button
aria-label="Clear search"
class="z-30 w-6 h-6 text-indigo-600 hover:text-indigo-700 active:text-indigo-700 absolute right-2 my-auto top-1/2 transform -translate-y-1/2"
on:click={clearSearch}
>
<CircleX />
</button>
</div>
{/if}
</div> -->

{#if $stops}
{#each $stops as stop (stop?.id)}
<Trigger {stop} />
{/each}
{/if}

<div slot="bus">
{#if $bus_stops}
{#each $bus_stops as stop (stop?.id)}
<BusTrigger {stop} />
{/each}
{/if}
</div>

<!-- TODO: prevent virtual keyboard from blocking results (use window.visualViewport.height to calculate max height of stops list or virtual keyboard api whenever that comes out) -->
{#if show_search && search === 'ready'}
<div class="relative">
<input
bind:this={search_el}
bind:value={search_term}
on:input={debounce(searchStops)}
type="search"
placeholder="Search stops"
class="search-stops text-indigo-200 max-w-[calc(100vw-10px)] pl-10 z-20 w-full h-12 rounded bg-neutral-900 shadow-2xl border-neutral-800/20 ring-1 ring-inset ring-neutral-700 placeholder:text-neutral-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600"
/>
<button
aria-label="Clear search"
class="z-30 w-6 h-6 text-indigo-600 hover:text-indigo-700 active:text-indigo-700 absolute right-2 my-auto top-1/2 transform -translate-y-1/2"
on:click={clearSearch}
>
<CircleX />
</button>
</div>
{/if}
<!-- </div> -->
</List>

<style lang="postcss">
Expand Down
13 changes: 12 additions & 1 deletion frontend/src/lib/components/Stop/Routes.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,21 @@
export let routes: RouteStop[];
export let link: boolean = false;
// sort routes so part time are last
const routes_s = routes.sort((a, b) => {
if (a.stop_type === StopType.PartTime && b.stop_type !== StopType.PartTime) {
return -1;
}
if (a.stop_type !== StopType.PartTime && b.stop_type === StopType.PartTime) {
return 1;
}
return 0;
});
</script>

<div class="flex gap-1">
{#each routes as route (route.id)}
{#each routes_s as route (route.id)}
<Icon
class={route.stop_type === StopType.FullTime || route.stop_type === StopType.PartTime
? ''
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/lib/components/TriggerButton.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

<button
id="list-item"
class="w-full flex justify-between items-center py-1 border-neutral-600 bg-neutral-700 rounded border shadow-2xl hover:bg-neutral-900 px-1"
class="w-full flex justify-between items-center py-1 shadow-2xl px-1"
transition:slide={{ easing: quintOut, axis: 'y', duration: 100 }}
on:click={() => {
pushState('', state);
Expand Down
2 changes: 0 additions & 2 deletions frontend/src/lib/components/Trip/StopTimeList.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,9 @@
st.eta = eta;
return st;
});
// .sort((a, b) => a.eta! - b.eta!);
});
</script>

<!-- <div class="flex gap-1 flex-col overflow-auto max-h-96"> -->
<List>
{#if $stop_times.length}
{#each $stop_times as stop_time (stop_time.trip_id)}
Expand Down
16 changes: 13 additions & 3 deletions frontend/src/lib/components/Trip/Trigger.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { TrainStatus, type Stop, type StopTime } from '$lib/api';
import { stops, stop_times, trips } from '$lib/stores';
import Icon from '$lib/components/Icon.svelte';
import TriggerButton from '$lib/components/TriggerButton.svelte';
// export let stop: Stop;
export let stop_time: StopTime;
Expand All @@ -22,17 +23,25 @@
// $: stops_away = $trip_stop_times.findIndex((st) => st.stop_id === stop_time.stop_id);
</script>

<TriggerButton
state={{
dialog_open: true,
dialog_id: stop_time.trip_id,
dialog_type: 'trip'
}}
>
<!--
<button
id="list-item"
class="w-full border-y border-neutral-400 mt-[-1px] p-[.5rem] flex justify-between items-center text-indigo-200 px-1"
class="w-full py-2 flex justify-between items-center text-indigo-200 px-1"
on:click={() => {
pushState('', {
dialog_open: true,
dialog_id: stop_time.trip_id,
dialog_type: 'trip'
});
}}
>
> -->
<!-- <div
class="w-full border-neutral-700 bg-neutral-800 rounded border shadow-2xl hover:bg-neutral-900 px-1 text-neutral-300"
> -->
Expand Down Expand Up @@ -60,4 +69,5 @@
{last_stop?.name}
</div>
<!-- </div> -->
</button>
<!-- </button> -->
</TriggerButton>
14 changes: 7 additions & 7 deletions frontend/src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -128,23 +128,23 @@
title="Nearby Stops"
show_location={true}
>
<div slot="location" class="flex gap-2">
<div slot="location">
{#if $location_status === LocationStatus.Loading}
<div class="flex gap-1 items-center text-white rounded px-2 py-1 bg-indigo-600">
<Locate class="w-4 h-4 animate-spin" />
<div class="flex gap-1 items-center text-white rounded p-1 bg-indigo-600">
<Locate class="animate-spin" />
</div>
{:else}
<button
aria-label="Nearby stops"
class="items-center bg-indigo-500 text-white rounded px-2 py-1 active:bg-indigo-600 hover:bg-indigo-600"
class="items-center bg-indigo-500 text-white rounded p-1 active:bg-indigo-600 hover:bg-indigo-600"
on:click={get_nearby_stops}
>
{#if $location_status === LocationStatus.Denied}
<LocateOff class="w-4 h-4" />
<LocateOff />
{:else if $location_status === LocationStatus.Granted}
<LocateFixed class="w-4 h-4" />
<LocateFixed />
{:else}
<Locate class="w-4 h-4" />
<Locate />
{/if}
</button>
{/if}
Expand Down

0 comments on commit e790ba9

Please sign in to comment.