143 lines
3.3 KiB
Svelte
143 lines
3.3 KiB
Svelte
<script>
|
|
import { initAuth, getLoading, getUser, getNeedsCountry } from './lib/auth/userStore.svelte.js';
|
|
import LoginOverlay from './lib/auth/LoginOverlay.svelte';
|
|
import CountryPicker from './lib/auth/CountryPicker.svelte';
|
|
import Layout from './lib/layout/Layout.svelte';
|
|
import WorldMap from './lib/world-map/WorldMap.svelte';
|
|
import JourneyView from './lib/world-map/JourneyView.svelte';
|
|
import StatsPanel from './lib/world-map/StatsPanel.svelte';
|
|
import TimelineView from './lib/timeline/TimelineView.svelte';
|
|
|
|
let screen = $state('worldmap');
|
|
let journeyActive = $state(false);
|
|
let journeyProgress = $state(null);
|
|
let inDetail = $state(false);
|
|
let pendingCountry = $state('');
|
|
let journeyMode = $state('map');
|
|
|
|
function onNavigate(s) {
|
|
screen = s;
|
|
}
|
|
|
|
function startJourney() {
|
|
journeyActive = true;
|
|
journeyProgress = null;
|
|
}
|
|
|
|
function endJourney() {
|
|
journeyActive = false;
|
|
journeyProgress = null;
|
|
}
|
|
|
|
function onJourneyProgress(p) {
|
|
journeyProgress = p;
|
|
}
|
|
|
|
function handleCountryClick(name) {
|
|
pendingCountry = name;
|
|
screen = 'timeline';
|
|
}
|
|
|
|
$effect(() => {
|
|
initAuth();
|
|
});
|
|
|
|
let loading = $derived(getLoading());
|
|
let user = $derived(getUser());
|
|
let needsCountry = $derived(getNeedsCountry());
|
|
</script>
|
|
|
|
{#if loading}
|
|
<div class="loading-screen">
|
|
<span class="loading-text">Loading...</span>
|
|
</div>
|
|
{:else}
|
|
<Layout {screen} {onNavigate} hideTopBar={inDetail}>
|
|
{#if screen === 'worldmap'}
|
|
<div class="worldmap-page">
|
|
<div class="map-area">
|
|
{#if journeyActive}
|
|
<JourneyView onclose={endJourney} onprogress={onJourneyProgress} mode={journeyMode} onmodechange={(m) => journeyMode = m} />
|
|
{:else}
|
|
<WorldMap onCountryClick={handleCountryClick} />
|
|
<button class="journey-play-btn" onclick={startJourney}>▶ Replay My Trips</button>
|
|
{/if}
|
|
</div>
|
|
<StatsPanel />
|
|
</div>
|
|
{:else}
|
|
<TimelineView
|
|
onDetailChange={(v) => (inDetail = v)}
|
|
{pendingCountry}
|
|
onNewEntryClear={() => (pendingCountry = '')}
|
|
/>
|
|
{/if}
|
|
</Layout>
|
|
|
|
{#if !user}
|
|
<LoginOverlay />
|
|
{:else if needsCountry}
|
|
<CountryPicker />
|
|
{/if}
|
|
{/if}
|
|
|
|
<style>
|
|
.loading-screen {
|
|
width: 100vw;
|
|
height: 100vh;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: #0f172a;
|
|
}
|
|
|
|
.loading-text {
|
|
font: 400 18px/1.4 sans-serif;
|
|
color: #94a3b8;
|
|
}
|
|
|
|
.worldmap-page {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: row;
|
|
min-width: 0;
|
|
height: 100%;
|
|
}
|
|
|
|
.map-area {
|
|
flex: 1;
|
|
overflow: hidden;
|
|
position: relative;
|
|
}
|
|
|
|
.journey-play-btn {
|
|
position: absolute;
|
|
bottom: 24px;
|
|
right: 24px;
|
|
z-index: 10;
|
|
padding: 12px 28px;
|
|
border-radius: 24px;
|
|
border: none;
|
|
background: #8b5cf6;
|
|
color: #fff;
|
|
font-size: 15px;
|
|
font-weight: 600;
|
|
gap: 6px;
|
|
cursor: pointer;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
box-shadow: 0 2px 12px rgba(139, 92, 246, 0.4);
|
|
transition: background 0.15s ease, transform 0.1s ease, box-shadow 0.15s ease;
|
|
}
|
|
|
|
.journey-play-btn:hover {
|
|
background: #7c3aed;
|
|
box-shadow: 0 4px 18px rgba(139, 92, 246, 0.55);
|
|
}
|
|
|
|
.journey-play-btn:active {
|
|
transform: scale(0.92);
|
|
}
|
|
</style>
|