feat: additional valve input types

This commit is contained in:
Timothy Jaeryang Baek 2025-07-02 17:45:42 +04:00
parent 7adb15d4b0
commit f55e93cabe
4 changed files with 140 additions and 1 deletions

7
package-lock.json generated
View File

@ -54,6 +54,7 @@
"jspdf": "^3.0.0",
"katex": "^0.16.22",
"kokoro-js": "^1.1.1",
"leaflet": "^1.9.4",
"marked": "^9.1.0",
"mermaid": "^11.6.0",
"paneforge": "^0.0.6",
@ -8065,6 +8066,12 @@
"node": ">=10.13.0"
}
},
"node_modules/leaflet": {
"version": "1.9.4",
"resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz",
"integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==",
"license": "BSD-2-Clause"
},
"node_modules/levn": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",

View File

@ -98,6 +98,7 @@
"jspdf": "^3.0.0",
"katex": "^0.16.22",
"kokoro-js": "^1.1.1",
"leaflet": "^1.9.4",
"marked": "^9.1.0",
"mermaid": "^11.6.0",
"paneforge": "^0.0.6",

View File

@ -4,6 +4,8 @@
const i18n = getContext('i18n');
import Switch from './Switch.svelte';
import MapSelector from './Valves/MapSelector.svelte';
import { split } from 'postcss/lib/list';
export let valvesSpec = null;
export let valves = {};
@ -49,7 +51,7 @@
{#if (valves[property] ?? null) !== null}
<!-- {valves[property]} -->
<div class="flex mt-0.5 mb-1.5 space-x-2">
<div class="flex mt-0.5 mb-0.5 space-x-2">
<div class=" flex-1">
{#if valvesSpec.properties[property]?.enum ?? null}
<select
@ -92,6 +94,61 @@
dispatch('change');
}}
/>
{:else if valvesSpec.properties[property]?.input ?? null}
{#if valvesSpec.properties[property]?.input?.type === 'color'}
<div class="flex items-center space-x-2">
<div class="relative size-6">
<input
type="color"
class="size-6 rounded cursor-pointer border border-gray-200 dark:border-gray-700"
value={valves[property] ?? '#000000'}
on:input={(e) => {
// Convert the color value to uppercase immediately
valves[property] = e.target.value.toUpperCase();
dispatch('change');
}}
/>
</div>
<input
type="text"
class="flex-1 rounded-lg py-2 text-sm dark:text-gray-300 dark:bg-gray-850 outline-hidden border border-gray-100 dark:border-gray-850"
placeholder="Enter hex color (e.g. #FF0000)"
bind:value={valves[property]}
autocomplete="off"
disabled
on:change={() => {
dispatch('change');
}}
/>
</div>
{:else if valvesSpec.properties[property]?.input?.type === 'map'}
<!-- EXPERIMENTAL INPUT TYPE, DO NOT USE IN PRODUCTION -->
<div class="flex flex-col items-center gap-1">
<MapSelector
setViewLocation={((valves[property] ?? '').includes(',') ?? false)
? valves[property].split(',')
: null}
onClick={(value) => {
valves[property] = value;
dispatch('change');
}}
/>
{#if valves[property]}
<input
type="text"
class=" w-full rounded-lg py-1 text-left text-sm dark:text-gray-300 dark:bg-gray-850 outline-hidden border border-gray-100 dark:border-gray-850"
placeholder="Enter coordinates (e.g. 51.505, -0.09)"
bind:value={valves[property]}
autocomplete="off"
on:change={() => {
dispatch('change');
}}
/>
{/if}
</div>
{/if}
{:else}
<textarea
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-hidden border border-gray-100 dark:border-gray-850"

View File

@ -0,0 +1,74 @@
<script>
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import { onMount, onDestroy } from 'svelte';
let map;
let mapElement;
export let setViewLocation = [51.505, -0.09];
export let points = [];
export let onClick = (e) => {};
let markerGroupLayer = null;
const setMarkers = (points) => {
if (map) {
if (markerGroupLayer) {
map.removeLayer(markerGroupLayer);
}
let markers = [];
for (let point of points) {
const marker = L.marker(point.coords).bindPopup(point.content);
markers.push(marker);
}
markerGroupLayer = L.featureGroup(markers).addTo(map);
try {
map.fitBounds(markerGroupLayer.getBounds(), {
maxZoom: 13
});
} catch (error) {
console.error('Error fitting bounds for markers:', error);
}
}
};
onMount(async () => {
map = L.map(mapElement).setView(setViewLocation ? setViewLocation : [51.505, -0.09], 10);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution:
'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
setMarkers(points);
map.on('click', (e) => {
console.log(e.latlng);
onClick(`${e.latlng.lat}, ${e.latlng.lng}`);
setMarkers([
{
coords: [e.latlng.lat, e.latlng.lng],
content: `Lat: ${e.latlng.lat}, Lng: ${e.latlng.lng}`
}
]);
});
});
onDestroy(async () => {
if (map) {
console.log('Unloading Leaflet map.');
map.remove();
}
});
</script>
<div class=" z-10 w-full">
<div bind:this={mapElement} class="h-96 z-10" />
</div>