Compare commits
2 commits
f4b397043a
...
87f0a53cb5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87f0a53cb5 | ||
|
|
3d609771de |
5 changed files with 157 additions and 23 deletions
|
|
@ -20,7 +20,7 @@
|
|||
let selectedProfile: ProfileName = "Normal";
|
||||
let startPoint = "Custom";
|
||||
|
||||
export let element: HTMLDivElement | null = null;
|
||||
let element: HTMLDivElement | null = null;
|
||||
|
||||
const now = new Date();
|
||||
let startDate = now.toISOString().split("T")[0]; // YYYY-MM-DD
|
||||
|
|
@ -53,6 +53,10 @@
|
|||
}
|
||||
};
|
||||
|
||||
export let handleClickSelectOnMap = () => {
|
||||
console.log("Select on map clicked");
|
||||
}
|
||||
|
||||
const applyCoordinatesFromInput = () => {
|
||||
const lat = parseFloat(inputLat);
|
||||
const lng = parseFloat(inputLng);
|
||||
|
|
@ -80,8 +84,8 @@
|
|||
$FlightParametersStore.launch_latitude = lat;
|
||||
$FlightParametersStore.launch_longitude = lng;
|
||||
console.log("Launch position updated:", lat, lng);
|
||||
inputLat = lat.toString();
|
||||
inputLng = lng.toString();
|
||||
inputLat = lat.toFixed(6).toString();
|
||||
inputLng = lng.toFixed(6).toString();
|
||||
};
|
||||
|
||||
export const getElement = () => {
|
||||
|
|
@ -89,7 +93,11 @@
|
|||
};
|
||||
</script>
|
||||
|
||||
<div bind:this={element} style="width: 23rem; max-height: 80vh; overflow-y: auto; z-index: 1000;" class="position-absolute shadow-lg bottom-0 end-0 m-3">
|
||||
<div
|
||||
bind:this={element}
|
||||
style="width: 23rem; max-height: 80vh; overflow-y: auto; z-index: 1000;"
|
||||
class="position-absolute shadow-lg panel-container"
|
||||
>
|
||||
<Card>
|
||||
<CardHeader
|
||||
class="bg-primary text-white d-flex justify-content-between align-items-center card-header"
|
||||
|
|
@ -221,7 +229,7 @@
|
|||
color="outline-secondary"
|
||||
size="sm"
|
||||
class="w-100"
|
||||
on:click={() => console.log("Select on map clicked")}>Указать на карте</Button
|
||||
on:click={ handleClickSelectOnMap }>Указать на карте</Button
|
||||
>
|
||||
</FormGroup>
|
||||
|
||||
|
|
|
|||
97
src/routes/Toast.svelte
Normal file
97
src/routes/Toast.svelte
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
<script context="module">
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
/**
|
||||
* @typedef {'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info' | 'light' | 'dark'} ToastColor
|
||||
* @typedef {object} ToastMessage
|
||||
* @property {string} id - Unique identifier
|
||||
* @property {string} header - Toast title
|
||||
* @property {string} body - Toast message content
|
||||
* @property {ToastColor} [color='info'] - The color of the toast header icon
|
||||
* @property {boolean} [persistent=false] - If true, toast will not auto-close
|
||||
* @property {function} [onRemoveCallback=null] - Callback function to be called when the toast is removed
|
||||
*/
|
||||
|
||||
/** @type {import('svelte/store').Writable<ToastMessage[]>} */
|
||||
export const toasts = writable([]);
|
||||
|
||||
/**
|
||||
* Adds a new toast to the list.
|
||||
* @param {Omit<ToastMessage, 'id'>} toast
|
||||
* @returns {string} The ID of the new toast.
|
||||
*/
|
||||
export function addToast(toast) {
|
||||
const id = crypto.randomUUID();
|
||||
toasts.update((all) => [...all, { id, ...toast }]);
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a toast by its ID.
|
||||
* @param {string} id
|
||||
*/
|
||||
export function removeToast(id) {
|
||||
// call the onRemoveCallback if it exists
|
||||
toasts.update((all) => {
|
||||
const toast = all.find((t) => t.id === id);
|
||||
if (toast && toast.onRemoveCallback) {
|
||||
toast.onRemoveCallback(id);
|
||||
}
|
||||
return all.filter((t) => t.id !== id);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function to be called when a toast is removed.
|
||||
* @param {string} id - The ID of the removed toast.
|
||||
*/
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { Toast, ToastBody, ToastHeader } from '@sveltestrap/sveltestrap';
|
||||
|
||||
/**
|
||||
* Removes a toast from the list by its ID.
|
||||
* @param {string} id
|
||||
*/
|
||||
|
||||
</script>
|
||||
|
||||
<!--
|
||||
This container holds all the toasts.
|
||||
To use this component:
|
||||
1. Import it into your layout or page: `import ToastContainer from './Toast.svelte';`
|
||||
2. Place `<ToastContainer />` in your markup.
|
||||
3. To show a toast from any other component:
|
||||
import { addToast } from './Toast.svelte';
|
||||
|
||||
// For an auto-closing error message
|
||||
addToast({ header: 'Error', body: 'Something went wrong.', color: 'danger' });
|
||||
|
||||
// For a persistent "map mode" indication
|
||||
addToast({ header: 'Map Mode', body: 'You are in satellite view.', color: 'info', persistent: true });
|
||||
-->
|
||||
<div class="toast-container position-fixed bottom-0 end-0 p-3">
|
||||
{#each $toasts as toast (toast.id)}
|
||||
<Toast
|
||||
isOpen={true}
|
||||
autohide={!toast.persistent}
|
||||
delay={5000}
|
||||
color={toast.color || 'info'}
|
||||
on:close={() => removeToast(toast.id)}
|
||||
>
|
||||
<ToastHeader toggle={() => removeToast(toast.id)}>
|
||||
{toast.header}
|
||||
</ToastHeader>
|
||||
<ToastBody>
|
||||
{toast.body}
|
||||
</ToastBody>
|
||||
</Toast>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.toast-container {
|
||||
z-index: 1090; /* High z-index to appear above other elements */
|
||||
}
|
||||
</style>
|
||||
|
|
@ -7,8 +7,6 @@
|
|||
import { distHaversine } from "../lib/mathutil.ts";
|
||||
import type { PredictionData, TelemetryData } from "../lib/types.ts";
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @type {'prediction' | 'telemetry'}
|
||||
*/
|
||||
|
|
@ -145,9 +143,7 @@
|
|||
{mouseLng.toFixed(6)}
|
||||
</p>
|
||||
</div>
|
||||
<div class="panel-container">
|
||||
<slot />
|
||||
</div>
|
||||
<slot />
|
||||
{#if map && windData}
|
||||
<WindVisualization {map} windData={windData} />
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
<script lang="ts">
|
||||
import Map from '../Map.svelte';
|
||||
import ControlPanel from '../ControlPanel.svelte';
|
||||
import Navbar from '../Navbar.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import { PredictionStore } from '$lib/stores';
|
||||
import { Modal } from '@sveltestrap/sveltestrap';
|
||||
import L from 'leaflet';
|
||||
|
||||
import Map from "../Map.svelte";
|
||||
import ControlPanel from "../ControlPanel.svelte";
|
||||
import Navbar from "../Navbar.svelte";
|
||||
import { onMount } from "svelte";
|
||||
import { PredictionStore } from "$lib/stores";
|
||||
import { Modal } from "@sveltestrap/sveltestrap";
|
||||
import { addToast, removeToast } from "../Toast.svelte"
|
||||
import ToastContainer from '../Toast.svelte';
|
||||
import L from "leaflet";
|
||||
|
||||
let map: Map | null = null;
|
||||
let panel: ControlPanel | null = null;
|
||||
let selectionToastId: string | null = null;
|
||||
|
||||
onMount(() => {
|
||||
PredictionStore.subscribe((data) => {
|
||||
|
|
@ -17,7 +19,7 @@
|
|||
map?.clearMapLayers();
|
||||
}
|
||||
});
|
||||
console.log('ControlPanel mounted');
|
||||
console.log("ControlPanel mounted");
|
||||
console.log(panel);
|
||||
|
||||
if (panel) {
|
||||
|
|
@ -26,11 +28,42 @@
|
|||
L.DomEvent.disableScrollPropagation(element);
|
||||
}
|
||||
});
|
||||
|
||||
function handleClickSelectOnMap() {
|
||||
if (map) {
|
||||
map.startSelection();
|
||||
console.log("Selection mode enabled");
|
||||
if (!selectionToastId) {
|
||||
selectionToastId = addToast({
|
||||
header: "Selection Mode",
|
||||
body: "Click on the map to select a position.",
|
||||
color: "info",
|
||||
persistent: true,
|
||||
onRemoveCallback: () => {
|
||||
selectionToastId = null;
|
||||
map?.stopSelection();
|
||||
console.log("Selection mode disabled");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleCoordinateSelection(event: CustomEvent<{ lat: number; lng: number }>) {
|
||||
const { lat, lng } = event.detail;
|
||||
panel?.updateLaunchPosition(lat, lng);
|
||||
console.log(`Selected coordinates: ${lat}, ${lng}`);
|
||||
if (selectionToastId) {
|
||||
removeToast(selectionToastId);
|
||||
selectionToastId = null;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<main>
|
||||
<Navbar />
|
||||
<Map bind:this={map} mode="prediction" bind:data={$PredictionStore}>
|
||||
<ControlPanel bind:this={panel} />
|
||||
<Map bind:this={map} mode="prediction" bind:data={$PredictionStore} on:coordinatesSelected={handleCoordinateSelection}>
|
||||
<ControlPanel bind:this={panel} {handleClickSelectOnMap} />
|
||||
<ToastContainer />
|
||||
</Map>
|
||||
</main>
|
||||
|
|
@ -78,6 +78,6 @@
|
|||
.panel-container {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
left: 20px;
|
||||
z-index: 1000;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue