diff --git a/DEBUGGING_WIND_LAYER.md b/DEBUGGING_WIND_LAYER.md deleted file mode 100644 index 7842dd0..0000000 --- a/DEBUGGING_WIND_LAYER.md +++ /dev/null @@ -1,318 +0,0 @@ -# Wind Layer Debugging Guide - -## ✅ Fixes Applied - -### 1. **Removed Leaflet Dependencies** -- ❌ Deleted `src/lib/ext/leaflet-ruler/leaflet-ruler.ts` -- This file was causing import errors for missing 'leaflet' module - -### 2. **Fixed Type Definitions** -**File:** `src/lib/types.ts` - -**Before:** -```typescript -export type LatLngTuple = [number, number]; -``` - -**After:** -```typescript -export type LatLngTuple = [number, number] | [number, number, number]; // Support 2D and 3D -export interface LatLngLiteral { - lat: number; - lng: number; - alt?: number; // Optional altitude -} -``` - -**Why:** Prediction and telemetry data includes altitude (3D coordinates), so types need to support `[lat, lng, alt]` tuples. - -### 3. **Dev Server Status** -✅ **Server running successfully** on `http://localhost:5175/` -✅ No build errors in console -✅ Wind layer package installed: `@sakitam-gis/maplibre-wind@2.0.3` - ---- - -## 🔍 Debugging 500 Internal Server Error - -If you're still seeing a 500 error, check these areas: - -### 1. **Check Browser Console** - -Open browser DevTools (F12) and look for: - -```javascript -// Expected success logs: -"WindVisualization mounted with MapLibre map" -"Wind data available: Array(2)" -"Wind data stats - U: [-21.32, 26.80], V: [-21.57, 21.42]" -"Wind layers initialized successfully" - -// Error logs to watch for: -"Failed to process wind data" -"Error initializing wind layers:" -"Missing U or V wind components" -``` - -### 2. **Check Network Tab** - -Look for failed requests: -- `/src/routes/testVelo.json` - Wind data file -- MapLibre GL CSS/JS assets -- Wind layer assets - -### 3. **Verify Wind Data File** - -```bash -# Check if file exists -ls -la src/routes/testVelo.json - -# Check file size (should be ~76KB) -du -h src/routes/testVelo.json - -# Verify JSON is valid -cat src/routes/testVelo.json | python -m json.tool > /dev/null && echo "Valid JSON" || echo "Invalid JSON" -``` - -### 4. **Check Map Component** - -The Map component should pass both props: - -```svelte - -``` - -Verify in `src/lib/components/Map.svelte`: -- Line ~155-157: WindVisualization component exists -- `windData` is loaded from fetch -- `map` instance is created - -### 5. **SSR (Server-Side Rendering) Issues** - -MapLibre and wind-layer are client-only. Ensure: - -```typescript -// In +page.ts or +page.server.ts -export const ssr = false; -``` - -Check: `src/routes/predict/+page.ts` - -### 6. **Build Issues** - -Try clearing cache and rebuilding: - -```bash -# Clear SvelteKit cache -rm -rf .svelte-kit - -# Clear node_modules (if needed) -rm -rf node_modules -npm install - -# Restart dev server -npm run dev -``` - ---- - -## 🧪 Test Cases - -### Test 1: Component Loads -1. Navigate to `/predict` -2. Open console (F12) -3. Look for "WindVisualization mounted" message -4. ✅ Success if no errors - -### Test 2: Wind Data Loaded -1. Check console for "Wind data available: Array(2)" -2. Verify data has U-component (parameterNumber: 2) -3. Verify data has V-component (parameterNumber: 3) -4. ✅ Success if both components present - -### Test 3: Layers Initialize -1. Look for "Wind layers initialized successfully" -2. Check map has particle animation visible -3. Toggle checkboxes work -4. ✅ Success if particles animate - -### Test 4: No Console Errors -1. Check for any red errors in console -2. Common errors: - - `Cannot read properties of undefined` - - `Module not found` - - `addLayer is not a function` -3. ✅ Success if no errors - ---- - -## 🐛 Common Errors & Solutions - -### Error: "Cannot find module '@sakitam-gis/maplibre-wind'" - -**Solution:** -```bash -npm install @sakitam-gis/maplibre-wind --save -``` - -### Error: "map.addLayer is not a function" - -**Cause:** Map not fully initialized - -**Solution:** Component already waits for map load: -```javascript -if (map.loaded()) { - initializeWindLayers(); -} else { - map.on('load', initializeWindLayers); -} -``` - -### Error: "Missing U or V wind components" - -**Cause:** Wind data file corrupted or wrong format - -**Solution:** Verify `testVelo.json` has 2 objects with: -- First: `header.parameterNumber: 2` (U-component) -- Second: `header.parameterNumber: 3` (V-component) - -### Error: "Failed to process wind data" - -**Cause:** Data structure doesn't match expected format - -**Solution:** Check data has: -```javascript -{ - header: { nx, ny, parameterNumber }, - data: [/* array of numbers */] -} -``` - -### Error: Layer already exists - -**Cause:** Trying to add layer that's already on map - -**Solution:** Component checks before adding: -```javascript -if (!map.getLayer('wind-particles')) { - map.addLayer(particleLayer); -} -``` - ---- - -## 📊 Expected Console Output - -### Successful Load: -``` -WindVisualization mounted with MapLibre map -Wind data available: Array(2) [{header: {…}, data: Array(65160)}, {header: {…}, data: Array(65160)}] -Wind data stats - U: [-21.32, 26.80], V: [-21.57, 21.42] -Processed wind data: {uMin: -21.32, uMax: 26.8, vMin: -21.57, vMax: 21.42, rows: 181, cols: 360, data: Array(2)} -Wind layers initialized successfully -``` - -### Layer Toggle: -``` -// When unchecking particle layer -(Removes layer from map) - -// When checking particle layer -(Adds layer back to map) -``` - ---- - -## 🔧 Manual Testing - -### Test in Browser Console - -```javascript -// 1. Check if map has wind layers -map.getLayer('wind-particles') // Should return layer object -map.getLayer('wind-heatmap') // Should return layer object - -// 2. Check if map instance is valid -map.loaded() // Should return true - -// 3. Manually toggle layers -map.removeLayer('wind-particles') -map.addLayer(particleLayer) // If you have reference -``` - ---- - -## 📝 Code Review Checklist - -### WindVisualisation.svelte -- [x] Uses `$props()` (Svelte 5 syntax) -- [x] Has `prepareWindData()` function -- [x] Waits for map load -- [x] Has error handling (try/catch) -- [x] Cleans up on destroy -- [x] Reactive `$effect()` for toggles - -### Map.svelte -- [x] Imports WindVisualization component -- [x] Fetches wind data from testVelo.json -- [x] Passes `map` and `windData` props -- [x] Renders WindVisualization component - -### types.ts -- [x] Supports 3D coordinates `[lat, lng, alt]` -- [x] Optional `alt` in LatLngLiteral -- [x] Proper LatLngExpression type - ---- - -## 🚀 Performance Notes - -### Particle Count Impact - -```javascript -// High performance (2000-3000 particles) -numParticles: 2000 - -// Balanced (5000 particles) - Default -numParticles: 5000 - -// High quality (10000+ particles) - May lag on slower devices -numParticles: 10000 -``` - -### Large Datasets - -Current dataset: 65,160 points (360 × 181 grid) -- Should render in <1 second -- GPU-accelerated via WebGL -- No lag on modern browsers - ---- - -## 📚 Additional Resources - -- **Wind Layer Repo:** https://github.com/sakitam-fdd/wind-layer -- **MapLibre Docs:** https://maplibre.org/maplibre-gl-js/docs/ -- **Issue Tracker:** Report bugs in wind-layer repo - ---- - -## ✅ Final Checklist - -Before reporting an issue, verify: - -- [ ] Dev server running (`npm run dev`) -- [ ] No errors in terminal -- [ ] Browser console open (F12) -- [ ] No red errors in console -- [ ] testVelo.json file exists -- [ ] MapLibre GL loaded correctly -- [ ] Wind layer package installed -- [ ] Component props passed correctly -- [ ] SSR disabled for map routes - ---- - -**Last Updated:** December 2025 -**Status:** ✅ Implementation Complete -**Known Issues:** None diff --git a/WIND_LAYER_IMPLEMENTATION.md b/WIND_LAYER_IMPLEMENTATION.md deleted file mode 100644 index 9457025..0000000 --- a/WIND_LAYER_IMPLEMENTATION.md +++ /dev/null @@ -1,299 +0,0 @@ -# Wind Layer Implementation Guide - -## 🌬️ Overview - -The project now uses **[@sakitam-gis/maplibre-wind](https://github.com/sakitam-fdd/wind-layer)** for professional wind visualization on MapLibre GL maps. - -## 📦 Installation - -```bash -npm install @sakitam-gis/maplibre-wind --save -``` - -**Package installed:** ✅ Version included in `package.json` - -## 🎨 Features Implemented - -### Wind Particle Animation -- **5000 particles** flowing with wind direction -- **Color gradient:** Blue → Green → Yellow → Orange → Red -- **Smooth animation** with WebGL acceleration -- **Configurable speed** and fade effects - -### Heatmap Visualization -- **Color-coded intensity** display -- **Opacity control** (70% default) -- **Display range:** 0-20 m/s -- **Rainbow color scheme:** Blue → Cyan → Green → Yellow → Red - -## 🔧 Component Structure - -### File: `src/lib/components/WindVisualisation.svelte` - -**Props:** -- `map` - MapLibre GL map instance -- `windData` - Wind data in GRIB format (U/V components) - -**State:** -- `showHeatmap` - Toggle heatmap layer -- `showParticles` - Toggle particle animation layer - -**Functions:** -- `initializeWindLayers()` - Creates particle and heatmap layers -- `prepareWindData()` - Transforms GRIB data to wind-layer format -- Reactive `$effect()` - Toggles layer visibility - -## 📊 Data Format - -### Input: GRIB Wind Data (`testVelo.json`) - -```json -[ - { - "header": { - "parameterNumber": 2, // U-component - "nx": 360, // Grid columns - "ny": 181, // Grid rows - "lo1": 0.0, // Starting longitude - "la1": 90.0 // Starting latitude - }, - "data": [/* U-component values */] - }, - { - "header": { - "parameterNumber": 3, // V-component - ... - }, - "data": [/* V-component values */] - } -] -``` - -### Output: Wind-Layer Format - -```typescript -{ - uMin: number, // Min U-component value - uMax: number, // Max U-component value - vMin: number, // Min V-component value - vMax: number, // Max V-component value - rows: number, // Grid rows (ny) - cols: number, // Grid columns (nx) - data: [Array, Array] // [U-component, V-component] -} -``` - -## 🎛️ Configuration Options - -### Particle Layer - -```javascript -{ - renderType: 'particles', - styleSpec: { - numParticles: 5000, // Number of particles - fadeOpacity: 0.996, // Trail fade rate (0.9-0.999) - speedFactor: 0.25, // Animation speed multiplier - dropRate: 0.003, // Particle regeneration rate - dropRateBump: 0.01, // Regeneration boost - colors: [ // Color gradient - '#3288bd', // Blue - '#66c2a5', // Green - '#fee08b', // Yellow - '#f46d43', // Orange - '#d53e4f' // Red - ] - } -} -``` - -### Heatmap Layer - -```javascript -{ - renderType: 'colorize', - styleSpec: { - opacity: 0.7, - colors: [ - '#0000ff', // Blue - '#00ffff', // Cyan - '#00ff00', // Green - '#ffff00', // Yellow - '#ff0000' // Red - ], - displayRange: [0, 20] // Min/max wind speed (m/s) - } -} -``` - -## 🎮 Usage - -### UI Controls - -Located in bottom-left corner of the map: - -- ☑️ **Тепловая карта** - Toggle heatmap visualization -- ☑️ **Частицы ветра** - Toggle particle animation (default: ON) - -### Programmatic Control - -```typescript -// In Map.svelte - - -// Toggle layers via checkbox binding -// Layers automatically add/remove from map -``` - -## 🔄 Data Flow - -``` -1. testVelo.json (GRIB format) - ↓ -2. Map.svelte loads data - ↓ -3. WindVisualisation component receives: - - map instance - - windData - ↓ -4. prepareWindData() transforms to wind-layer format - ↓ -5. WindLayer instances created: - - Particle layer - - Heatmap layer - ↓ -6. Layers added to map - ↓ -7. User toggles visibility via checkboxes -``` - -## 🎯 Key Implementation Details - -### 1. Svelte 5 Runes - -Uses modern Svelte 5 syntax: -- `$props()` for component props -- `$state()` for reactive state -- `$effect()` for reactive layer toggling - -### 2. Map Lifecycle - -- Waits for map to load before initializing -- Checks `map.loaded()` status -- Listens to `'load'` event if not ready - -### 3. Layer Management - -- Checks if layer exists before adding -- Removes layers on component destroy -- Prevents duplicate layer IDs - -### 4. Error Handling - -- Validates wind data structure -- Catches initialization errors -- Logs detailed error messages -- Graceful degradation on failure - -## 🐛 Debugging - -### Console Logs - -```javascript -// On mount -"WindVisualization mounted with MapLibre map" -"Wind data available: [...]" - -// Data processing -"Wind data stats - U: [-21.32, 26.80], V: [-21.57, 21.42]" - -// Success -"Wind layers initialized successfully" - -// Errors -"Missing U or V wind components" -"Error initializing wind layers: [error]" -``` - -### Check Layer Status - -```javascript -// In browser console -map.getLayer('wind-particles') // Should return layer object -map.getLayer('wind-heatmap') // Should return layer object -``` - -## 📚 Resources - -- **GitHub:** https://github.com/sakitam-fdd/wind-layer -- **Examples:** https://sakitam-fdd.github.io/wind-layer/examples/ -- **MapLibre Docs:** https://maplibre.org/maplibre-gl-js/docs/ - -## ⚙️ Advanced Customization - -### Adjust Particle Count - -```javascript -numParticles: 10000 // More particles (slower performance) -numParticles: 2000 // Fewer particles (better performance) -``` - -### Change Animation Speed - -```javascript -speedFactor: 0.5 // Faster animation -speedFactor: 0.1 // Slower animation -``` - -### Custom Color Schemes - -```javascript -// Wind speed colors -colors: ['#000080', '#0000FF', '#FFFF00', '#FF0000', '#800000'] - -// Monochrome -colors: ['#FFFFFF', '#CCCCCC', '#999999', '#666666', '#000000'] -``` - -### Adjust Display Range - -```javascript -displayRange: [0, 30] // For stronger winds -displayRange: [0, 10] // For lighter winds -``` - -## 🚀 Future Enhancements - -Potential additions: -- Timeline control for temporal wind data -- Arrow vector visualization -- Wind speed labels -- Custom tile sources for real-time data -- Wind barbs (meteorological standard) -- Integration with prediction module - -## ✅ Testing Checklist - -- [x] Package installed successfully -- [x] Component imports without errors -- [x] Wind data loads from testVelo.json -- [x] Particle animation displays on map -- [x] Heatmap visualization works -- [x] Checkboxes toggle layers correctly -- [x] No console errors on mount/unmount -- [x] Layers clean up on component destroy - -## 📝 Notes - -- Wind data must be in GRIB format with U/V components -- Particle layer is GPU-accelerated (requires WebGL) -- Large particle counts may impact performance -- Data transformation happens client-side -- Layers are added above base map tiles -- Z-index managed by MapLibre layer order - ---- - -**Implementation Date:** December 2025 -**Package Version:** @sakitam-gis/maplibre-wind -**Status:** ✅ Production Ready diff --git a/src/lib/components/ControlPanel.svelte b/src/lib/components/ControlPanel.svelte index b57e49c..237b802 100644 --- a/src/lib/components/ControlPanel.svelte +++ b/src/lib/components/ControlPanel.svelte @@ -46,12 +46,16 @@ InputGroup, InputGroupText, Label, + Dropdown, + DropdownToggle, + DropdownMenu, + DropdownItem, } from "@sveltestrap/sveltestrap"; import { getSavedPoints, updatePoint } from "$lib/api/points"; - import { addToast } from "$lib/components/Toast.svelte"; - import PointEditor from "$lib/components/PointEditor.svelte"; - import SelectSearchable from "$lib/components/SelectSearchable.svelte"; + import { addToast } from "$lib/components/ui/Toast.svelte"; + import PointEditor from "$lib/components/editors/PointEditor.svelte"; + import SelectSearchable from "$lib/components/ui/SelectSearchable.svelte"; import { getForecast } from "$lib/prediction"; import { FlightParametersStore, @@ -61,7 +65,10 @@ flightParametersDefaults, } from "$lib/stores"; import { PROFILE_MAP, type FlightParameters, type SavedPoint } from "$lib/types"; - import CurveEditor from "./CurveEditor.svelte"; + import CurveEditor from "$lib/components/editors/CurveEditor.svelte"; + import SpoilerGroup from "$lib/components/ui/SpoilerGroup.svelte"; + import LabelGroup from "./ui/LabelGroup.svelte"; + import { toFixedNumber } from "$lib/mathutil"; // Props interface Props { @@ -75,6 +82,9 @@ let startTime = $state(readLocalStorage("startTime", "12:00:00")); let selectedPointId = $state($FlightParametersStore.start_point || -1); + let ascentProfile = $state("standard"); + let descentProfile = $state("standard"); + // Component References let pointEditorRef: PointEditor | null = null; let curveEditorRef: CurveEditor | null = null; @@ -159,23 +169,14 @@ }); } else { // Create new point - pointEditorRef?.openModalAndCreate( - null, - { - id: 0, - name: `New Point ${new Date().toLocaleString()}`, - lat: $FlightParametersStore.launch_latitude, - lon: $FlightParametersStore.launch_longitude, - alt: $FlightParametersStore.launch_altitude, - }, - true, - false, - (savedPoint) => { - if (savedPoint) { - handlePointSelection(savedPoint.id); - } - }, - ); + pointEditorRef?.open({ + id: 0, // Assuming 0 or a negative number indicates a new point + name: `New Point ${new Date().toLocaleString()}`, + lat: $FlightParametersStore.launch_latitude, + lon: $FlightParametersStore.launch_longitude, + alt: $FlightParametersStore.launch_altitude, + // The onSave callback is handled by the onSelectPoint prop on the component + }, false); } } @@ -198,8 +199,8 @@ // Public API export function updateLaunchPosition(lat: number, lng: number) { - $FlightParametersStore.launch_latitude = lat; - $FlightParametersStore.launch_longitude = lng; + $FlightParametersStore.launch_latitude = toFixedNumber(lat, 6); + $FlightParametersStore.launch_longitude = toFixedNumber(lng, 6); } export function loadFlightParameters(params: FlightParameters) { @@ -256,60 +257,32 @@ - + -
- handlePointSelection(e)} - options={$SavedPointsStore.map((point) => ({ - value: point.id, - label: `${point.name} ${point.id === selectedPointId && isPointDirty() ? "(изменено)" : ""}`, - }))} - placeholder="Новая точка..." - searchPlaceholder="Поиск по точкам..." /> - {#if selectedPointId !== -1} - - {/if} -
+ handlePointSelection(e)} + options={$SavedPointsStore.map((point) => ({ + value: point.id, + label: `${point.name} ${point.id === selectedPointId && isPointDirty() ? "(изменено)" : ""}`, + }))} + placeholder="Новая точка..." + clearable={true} + searchPlaceholder="Поиск по точкам..." /> +
-
- - - -
- @@ -332,6 +305,35 @@ +
+ + + + + + Сохранить как новую... + Удалить выбранную точку + + Сбросить изменения + + +
+
@@ -371,19 +373,120 @@
{:else} - -

Custom profile editor is not yet implemented.

- + + {:else if ascentProfile === "standard"} + + + + + + + + + {/if} + +
+ + + +
+ {#if descentProfile === "custom"} + + {}} + options={$SavedPointsStore.map((point) => ({ + value: point.id, + label: `test`, + }))} + clearable={true} + placeholder="Выбрать профиль..." + searchPlaceholder="Поиск по профилям..." /> + + + {:else if descentProfile === "standard"} + + + + + + + + + + {/if} + + {/if} -
- +
+ + + + + + Сохранить + Сохранить как новый... + + Сбросить настройки + +
{/if} - handlePointSelection(point.id)} /> - + + { + if (point) { + handlePointSelection(point.id); + } else { + handlePointSelection(-1); // Clear selection + } + }} /> diff --git a/src/lib/components/GenericPanel.svelte b/src/lib/components/GenericPanel.svelte new file mode 100644 index 0000000..a63e0c1 --- /dev/null +++ b/src/lib/components/GenericPanel.svelte @@ -0,0 +1,55 @@ + + + + + + + + {#if !isCollapsed} + + + + {/if} + diff --git a/src/lib/components/Map.svelte b/src/lib/components/Map.svelte index 6b84be9..adbef69 100644 --- a/src/lib/components/Map.svelte +++ b/src/lib/components/Map.svelte @@ -391,14 +391,14 @@
-
+ {#if map && windData} diff --git a/src/lib/components/PanelContainer.svelte b/src/lib/components/PanelContainer.svelte index 929cf92..f8988dd 100644 --- a/src/lib/components/PanelContainer.svelte +++ b/src/lib/components/PanelContainer.svelte @@ -1,11 +1,12 @@ -
+
diff --git a/src/lib/components/PointEditor.svelte b/src/lib/components/PointEditor.svelte deleted file mode 100644 index 0d2c79e..0000000 --- a/src/lib/components/PointEditor.svelte +++ /dev/null @@ -1,399 +0,0 @@ - - - - - - - - { - isConfirmationVisible = false; - handleDeletePoint(selectedPoint); - }} - oncancel={() => { - isConfirmationVisible = false; - }}> -

Вы уверены, что хотите удалить эту точку?

-
diff --git a/src/lib/components/ScenarioPanel.svelte b/src/lib/components/ScenarioPanel.svelte index e24bc04..d1c9b18 100644 --- a/src/lib/components/ScenarioPanel.svelte +++ b/src/lib/components/ScenarioPanel.svelte @@ -16,10 +16,10 @@ import type { SavedScenario } from "$lib/types"; import { getSavedScenarios, updateScenario, saveScenario } from "$lib/api/scenarios"; import { FlightParametersStore, writeLocalStorage, ScenarioStore, SavedScenarioStore } from "$lib/stores"; - import SelectSearchable from "$lib/components/SelectSearchable.svelte"; + import SelectSearchable from "$lib/components/ui/SelectSearchable.svelte"; import { onMount } from "svelte"; - import { addToast } from "./Toast.svelte"; - import ScenarioEditor from "./ScenarioEditor.svelte"; + import { addToast } from "./ui/Toast.svelte"; + import ScenarioEditor from "$lib/components/editors/ScenarioEditor.svelte"; let isCollapsed = $state(false); let scenarioUnsaved = $derived(checkScenarioUnsaved()); @@ -187,12 +187,13 @@ bind:selected={selectedScenarioId} placeholder="Новый сценарий..." searchPlaceholder="Поиск сценариев..." - on:change={() => { + clearable={true} + onChange={() => { if (!scenarioUnsaved) { handleApplySelectedScenario(false); } }} /> - + -->
+
+ + + + (isConfirmationVisible = false)}> +

Вы уверены, что хотите удалить {config.labels.item} "{selectedItem?.name}"?

+
diff --git a/src/lib/components/editors/PointEditor.svelte b/src/lib/components/editors/PointEditor.svelte new file mode 100644 index 0000000..1166054 --- /dev/null +++ b/src/lib/components/editors/PointEditor.svelte @@ -0,0 +1,166 @@ + + + onClose()} + onSave={(p) => onSave(p)} + onSelect={(p) => onSelectPoint(p)} + itemFactory={pointFactory} + {api} + {config}> + {#snippet tableHeader()} + + Название точки + Широта + Долгота + Высота + Действия + + {/snippet} + + {#snippet tableRow({ row })} + {row.name} + {row.lat.toFixed(5)} ° + {row.lon.toFixed(5)} ° + {row.alt} м + {/snippet} + + {#snippet formFields({ item })} +
+ + +
+
+ + + + Градусы + + + + + Градусы + + + + + Метры над ур. моря + +
+ {/snippet} +
diff --git a/src/lib/components/ScenarioEditor.svelte b/src/lib/components/editors/ScenarioEditor.svelte similarity index 98% rename from src/lib/components/ScenarioEditor.svelte rename to src/lib/components/editors/ScenarioEditor.svelte index b2ca67d..b24ceb7 100644 --- a/src/lib/components/ScenarioEditor.svelte +++ b/src/lib/components/editors/ScenarioEditor.svelte @@ -13,10 +13,10 @@ PaginationLink, } from "@sveltestrap/sveltestrap"; import { onMount } from "svelte"; - import { addToast } from "$lib/components/Toast.svelte"; + import { addToast } from "$lib/components/ui/Toast.svelte"; import type { SavedScenario } from "$lib/types"; import { FlightParametersStore, SavedScenarioStore } from "$lib/stores"; - import ConfirmationPrompt from "./ConfirmationPrompt.svelte"; + import ConfirmationPrompt from "../ConfirmationPrompt.svelte"; import { getSavedScenarios, saveScenario, updateScenario, deleteScenario } from "$lib/api/scenarios"; // Props diff --git a/src/lib/components/EditableCell.svelte b/src/lib/components/ui/EditableCell.svelte similarity index 100% rename from src/lib/components/EditableCell.svelte rename to src/lib/components/ui/EditableCell.svelte diff --git a/src/lib/components/ScenarioTemplateEditor.svelte b/src/lib/components/ui/InputClearable.svelte similarity index 100% rename from src/lib/components/ScenarioTemplateEditor.svelte rename to src/lib/components/ui/InputClearable.svelte diff --git a/src/lib/components/ui/LabelGroup.svelte b/src/lib/components/ui/LabelGroup.svelte new file mode 100644 index 0000000..ff55694 --- /dev/null +++ b/src/lib/components/ui/LabelGroup.svelte @@ -0,0 +1,37 @@ + + +
+ + +
+ {@render children?.()} +
+
+ + diff --git a/src/lib/components/SelectSearchable.svelte b/src/lib/components/ui/SelectSearchable.svelte similarity index 69% rename from src/lib/components/SelectSearchable.svelte rename to src/lib/components/ui/SelectSearchable.svelte index 2f98e88..d8fbee3 100644 --- a/src/lib/components/SelectSearchable.svelte +++ b/src/lib/components/ui/SelectSearchable.svelte @@ -1,8 +1,6 @@ @@ -116,16 +147,28 @@ > {selectedLabel || placeholder} + {#if clearable && selected != null} + + {/if} + {#if isOpen}