Skip to content

Commit

Permalink
Merge pull request #37 from OneBusAway/feat-search
Browse files Browse the repository at this point in the history
Search Feature [In-Progress]
  • Loading branch information
aaronbrethorst authored Sep 3, 2024
2 parents 157a972 + 8c11f9c commit abd0af4
Show file tree
Hide file tree
Showing 11 changed files with 274 additions and 34 deletions.
11 changes: 11 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"version": "0.2.0",
"configurations": [
{
"command": "npm run dev",
"name": "Run development server",
"request": "launch",
"type": "node-terminal"
}
]
}
19 changes: 3 additions & 16 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions src/app.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

.scroll-hidden {
-ms-overflow-style: none; /* Internet Explorer 10+ */
scrollbar-width: none; /* Firefox */
}
.scroll-hidden::-webkit-scrollbar {
display: none; /* Safari and Chrome */
}
22 changes: 17 additions & 5 deletions src/components/map/GoogleMap.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
export let showRoute = false;
export let showRouteMap = false;
export let showAllStops = true;
export let stop = null;
let selectedStopID = null;
const dispatch = createEventDispatcher();
Expand Down Expand Up @@ -85,6 +88,15 @@
markers = [];
}
$: if (stop && map) {
// TODO: make sure that these markers are deduped. i.e. we shouldn't
// show the same stop twice on the map
if (stop.id != selectedStopID) {
addMarker(stop);
map.setCenter({ lat: stop.lat, lng: stop.lon });
}
}
$: if (showAllStops) {
clearAllMarkers();
allStops.forEach((s) => addMarker(s));
Expand All @@ -102,16 +114,16 @@
function addMarker(s) {
const container = document.createElement('div');
document.body.appendChild(container);
function handleClick() {
pushState(`/stops/${s.id}`);
dispatch('stopSelected', { stop: s });
}
new StopMarker({
target: container,
props: {
stop: s,
onClick: handleClick
onClick: () => {
selectedStopID = s.id;
pushState(`/stops/${s.id}`);
dispatch('stopSelected', { stop: s });
}
}
});
Expand Down
77 changes: 72 additions & 5 deletions src/components/navigation/Header.svelte
Original file line number Diff line number Diff line change
@@ -1,15 +1,82 @@
<script>
import { PUBLIC_OBA_REGION_NAME, PUBLIC_OBA_LOGO_URL } from '$env/static/public';
import {
PUBLIC_OBA_REGION_NAME,
PUBLIC_OBA_LOGO_URL,
PUBLIC_OBA_SEARCH_ENABLED
} from '$env/static/public';
import ThemeSwitcher from '$lib/ThemeSwitch/ThemeSwitcher.svelte';
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
let searchInput = '';
async function handleSearch() {
if (searchInput.length > 2) {
try {
const response = await fetch(`/api/oba/search?query=${encodeURIComponent(searchInput)}`);
const results = await response.json();
console.log('Route results:', results.routeSearchResults);
console.log('Stop results:', results.stopSearchResults);
dispatch('searchResults', results);
} catch (error) {
console.error('Error fetching search results:', error);
}
}
}
const onHandleSearch = (event) => {
if (event.key === 'Enter') {
handleSearch();
}
};
</script>

<div
class="bg-blur-md flex items-center justify-between border-b border-neutral-300 bg-white/80 px-4 dark:bg-black dark:text-white"
>
<div class="px-2 py-2">
<a href="/">
<img src={PUBLIC_OBA_LOGO_URL} alt={PUBLIC_OBA_REGION_NAME} class="h-10 rounded-sm" />
</a>
<div class="flex items-center justify-center gap-4 px-2 py-2">
<div>
<a href="/">
<img src={PUBLIC_OBA_LOGO_URL} alt={PUBLIC_OBA_REGION_NAME} class="h-10 rounded-sm" />
</a>
</div>
{#if PUBLIC_OBA_SEARCH_ENABLED === 'true'}
<div class="mx-auto max-w-md">
<label
for="default-search"
class="sr-only mb-2 text-sm font-medium text-gray-900 dark:text-white">Search</label
>
<div class="relative">
<div class="pointer-events-none absolute inset-y-0 start-0 flex items-center ps-3">
<svg
class="h-4 w-4 text-gray-500 dark:text-gray-400"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 20 20"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z"
/>
</svg>
</div>
<input
type="search"
id="search"
class="block w-full rounded-full border border-gray-300 bg-gray-50 p-2 ps-10 text-sm text-gray-900 dark:border-gray-600 dark:placeholder-gray-400"
placeholder="Search a stop or route"
required
bind:value={searchInput}
on:keydown={onHandleSearch}
/>
</div>
</div>
{/if}
</div>
<div>
<ThemeSwitcher />
Expand Down
11 changes: 9 additions & 2 deletions src/components/navigation/ModalPane.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import { createEventDispatcher } from 'svelte';
import { pushState } from '$app/navigation';
export let stop = null;
const dispatch = createEventDispatcher();
function closePane() {
Expand All @@ -14,7 +16,12 @@
}
</script>

<div class="modal-pane" in:fly={{ y: 200, duration: 500 }} out:fly={{ y: 200, duration: 500 }}>
<div
class="modal-pane scroll-hidden"
style={stop ? 'z-index: 40' : 'z-index: 20'}
in:fly={{ y: 200, duration: 500 }}
out:fly={{ y: 200, duration: 500 }}
>
<div class="py-1 text-right">
<button
type="button"
Expand All @@ -32,7 +39,7 @@

<style lang="postcss">
.modal-pane {
@apply absolute bottom-0 left-0 z-40 w-full bg-transparent px-2 shadow-lg md:max-w-prose;
@apply absolute bottom-0 left-0 max-h-[40rem] w-full overflow-y-scroll bg-transparent px-2 shadow-lg md:max-w-prose;
@apply rounded-lg border-b-[1px] border-[#C6C6C8] bg-[#F3F2F8] dark:border-[1px] dark:border-[#C6C6C8] dark:border-opacity-15 dark:bg-black;
}
Expand Down
55 changes: 55 additions & 0 deletions src/components/search/SearchResults.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<script>
export let searchResults = null;
import { createEventDispatcher } from 'svelte';
import { compassDirection } from '$lib/formatters';
const dispatch = createEventDispatcher();
function handleStopClick(stop) {
dispatch('stopSelected', { stop });
}
function handleRouteClick(route) {
alert(`TODO: show route ${route.id}`);
}
</script>

<div class="p-2">
<h2 class="mb-4 text-xl font-semibold uppercase text-[#86858B]">Search Results</h2>

<h3 class="mb-2 text-lg font-semibold dark:text-white">Routes</h3>
{#if searchResults?.routeSearchResults?.list?.length > 0}
<ul class="overflow-hidden rounded-lg">
{#each searchResults.routeSearchResults.list as route}
<li>
<button
on:click={() => handleRouteClick(route)}
class="flex h-auto w-full items-center justify-between border-b-[1px] border-[#C6C6C8] bg-[#ffffff] p-4 hover:cursor-pointer hover:bg-[#e3e3e3] dark:border-[#313135] dark:bg-[#1c1c1c] dark:text-white hover:dark:bg-[#363636]"
>
{route.name || `Route ${route.id}`}
</button>
</li>
{/each}
</ul>
{:else}
<p>No routes found.</p>
{/if}

<h3 class="mb-2 mt-4 text-lg font-semibold dark:text-white">Stops</h3>
{#if searchResults?.stopSearchResults?.list?.length > 0}
<ul class="overflow-hidden rounded-lg">
{#each searchResults.stopSearchResults.list as stop}
<li>
<button
on:click={() => handleStopClick(stop)}
class="flex h-auto w-full items-center justify-between border-b-[1px] border-[#C6C6C8] bg-[#ffffff] p-4 hover:cursor-pointer hover:bg-[#e3e3e3] dark:border-[#313135] dark:bg-[#1c1c1c] dark:text-white hover:dark:bg-[#363636]"
>
{stop.name} ({compassDirection(stop.direction)})
</button>
</li>
{/each}
</ul>
{:else}
<p>No stops found.</p>
{/if}
</div>
22 changes: 22 additions & 0 deletions src/lib/formatters.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export function compassDirection(abbreviation) {
switch (abbreviation) {
case 'N':
return 'North';
case 'NE':
return 'Northeast';
case 'E':
return 'East';
case 'SE':
return 'Southeast';
case 'S':
return 'South';
case 'SW':
return 'Southwest';
case 'W':
return 'West';
case 'NW':
return 'Northwest';
default:
return abbreviation;
}
}
6 changes: 1 addition & 5 deletions src/routes/+layout.svelte
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
<script>
import '../app.css';
import Header from '../components/navigation/Header.svelte';
import { config } from '@fortawesome/fontawesome-svg-core';
import '@fortawesome/fontawesome-svg-core/styles.css'; // Import the CSS
import '@fortawesome/fontawesome-svg-core/styles.css';
config.autoAddCss = false; // Tell Font Awesome to skip adding the CSS automatically since it's being imported above
</script>

<div class="relative h-dvh w-full">
<div class="absolute left-0 right-0 top-0 z-40">
<Header />
</div>
<div>
<slot></slot>
</div>
Expand Down
Loading

0 comments on commit abd0af4

Please sign in to comment.