131 lines
3.3 KiB
Svelte
131 lines
3.3 KiB
Svelte
<script>
|
|
import { onMount } from 'svelte';
|
|
import MapView from '$lib/components/MapView.svelte';
|
|
|
|
import { getNearbyMessages } from '$lib/firebase/messages.js';
|
|
import { messagesStore } from '$lib/stores/messagesStore.js';
|
|
import { mapStore } from '$lib/stores/mapStore.js';
|
|
|
|
import BottomSheet from '$lib/components/BottomSheet.svelte';
|
|
import SidePanel from '$lib/components/SidePanel.svelte';
|
|
|
|
import ComposeSheet from '$lib/components/ComposeSheet.svelte';
|
|
|
|
let lat = $state();
|
|
let lng = $state();
|
|
let error = $state();
|
|
|
|
let windowWidth = $state(0);
|
|
|
|
let isMobile = $derived(windowWidth < 768);
|
|
|
|
onMount(() => {
|
|
if (!navigator.geolocation) {
|
|
error = "Your browser doesn't support geolocation :(";
|
|
return; // do nothing
|
|
}
|
|
navigator.geolocation.getCurrentPosition(
|
|
(position) => {
|
|
lat = position.coords.latitude;
|
|
lng = position.coords.longitude;
|
|
},
|
|
() => {
|
|
error = "Location access denied. Please enable location to use Overheard.";
|
|
}
|
|
);
|
|
// populate the messages store
|
|
navigator.geolocation.getCurrentPosition(
|
|
async (position) => {
|
|
const messages = await getNearbyMessages(position.coords.latitude, position.coords.longitude);
|
|
messagesStore.set(messages);
|
|
console.log('messages loaded:', $messagesStore);
|
|
}
|
|
);
|
|
});
|
|
|
|
|
|
</script>
|
|
|
|
<svelte:window bind:innerWidth={windowWidth} /> <!--this sends the windowWidth to our mobile checker -->
|
|
|
|
{#if error}
|
|
<p class="error">{error}</p>
|
|
{:else if lat && lng}
|
|
<MapView {lat} {lng} />
|
|
{:else}
|
|
<p class="loading">Looking for you...</p>
|
|
{/if}
|
|
|
|
<!-- map must fill the whole screen-->
|
|
{#if lat && lng}
|
|
<MapView {lat} {lng} />
|
|
{/if}
|
|
|
|
<!-- show the right panel based on mobile or desktop-->
|
|
{#if windowWidth < 768}
|
|
<BottomSheet message={$mapStore.selectedMessage} />
|
|
{:else}
|
|
<SidePanel message={$mapStore.selectedMessage} />
|
|
{/if}
|
|
|
|
<!--floating action button for adding a message-->
|
|
{#if !$mapStore.composing}
|
|
<button
|
|
class="fab"
|
|
class:shifted={isMobile && $mapStore.selectedMessage}
|
|
onclick={() => mapStore.set(
|
|
{selectedMessage: null, composing: true })}>
|
|
+
|
|
</button>
|
|
{/if}
|
|
|
|
<!--compose sheet (making a message)-->
|
|
{#if $mapStore.composing}
|
|
<ComposeSheet {lat} {lng} />
|
|
{/if}
|
|
|
|
|
|
<style>
|
|
:global(body) {
|
|
margin: 0;
|
|
padding: 0;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.error, .loading {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
height: 100vh;
|
|
font-family: Georgia, 'Times New Roman', Times, serif;
|
|
color: #666;
|
|
|
|
}
|
|
|
|
.fab {
|
|
position: fixed;
|
|
bottom: 2rem;
|
|
right: 1.5rem;
|
|
width: 56px;
|
|
height: 56px;
|
|
border-radius: 50%;
|
|
background: #111;
|
|
color: white;
|
|
font-size: 1.8rem;
|
|
border: none;
|
|
cursor: pointer;
|
|
box-shadow: 0 4px 16px rgba(0,0,0,0.25);
|
|
z-index: 150;
|
|
display: flex;
|
|
align-items:center;
|
|
justify-content: center;
|
|
line-height: 1;
|
|
transition: bottom 0.35s cubic-bezier(0.32, 0.72, 0, 1); /* match the sheet's slide timing */
|
|
}
|
|
|
|
/* lift it above the bottom sheet so it doesn't get covered, x position stays the same */
|
|
.fab.shifted {
|
|
bottom: 35vh;
|
|
}
|
|
|
|
</style> |