diff --git a/Logic/FeatureSource/PerLayerFeatureSourceSplitter.ts b/Logic/FeatureSource/PerLayerFeatureSourceSplitter.ts index f437a90d6..f562e9748 100644 --- a/Logic/FeatureSource/PerLayerFeatureSourceSplitter.ts +++ b/Logic/FeatureSource/PerLayerFeatureSourceSplitter.ts @@ -1,8 +1,7 @@ -import { FeatureSource, FeatureSourceForLayer } from "./FeatureSource" +import { FeatureSource, IndexedFeatureSource } from "./FeatureSource" import FilteredLayer from "../../Models/FilteredLayer" import SimpleFeatureSource from "./Sources/SimpleFeatureSource" import { Feature } from "geojson" -import { Utils } from "../../Utils" import { UIEventSource } from "../UIEventSource" /** @@ -10,9 +9,7 @@ import { UIEventSource } from "../UIEventSource" * If this is the case, multiple objects with a different _matching_layer_id are generated. * In any case, this featureSource marks the objects with _matching_layer_id */ -export default class PerLayerFeatureSourceSplitter< - T extends FeatureSourceForLayer = SimpleFeatureSource -> { +export default class PerLayerFeatureSourceSplitter { public readonly perLayer: ReadonlyMap constructor( layers: FilteredLayer[], @@ -23,6 +20,11 @@ export default class PerLayerFeatureSourceSplitter< } ) { const knownLayers = new Map() + /** + * Keeps track of the ids that are included per layer. + * Used to know if the downstream feature source needs to be pinged + */ + let layerIndexes: ReadonlySet[] = layers.map((_) => new Set()) this.perLayer = knownLayers const layerSources = new Map>() const constructStore = @@ -41,6 +43,12 @@ export default class PerLayerFeatureSourceSplitter< // We try to figure out (for each feature) in which feature store it should be saved. const featuresPerLayer = new Map() + /** + * Indexed on layer-position + * Will be true if a new id pops up + */ + const hasChanged: boolean[] = layers.map((_) => false) + const newIndices: Set[] = layers.map((_) => new Set()) const noLayerFound: Feature[] = [] for (const layer of layers) { @@ -49,9 +57,14 @@ export default class PerLayerFeatureSourceSplitter< for (const f of features) { let foundALayer = false - for (const layer of layers) { + for (let i = 0; i < layers.length; i++) { + const layer = layers[i] if (layer.layerDef.source.osmTags.matchesProperties(f.properties)) { + const id = f.properties.id // We have found our matching layer! + const previousIndex = layerIndexes[i] + hasChanged[i] = hasChanged[i] || !previousIndex.has(id) + newIndices[i].add(id) featuresPerLayer.get(layer.layerDef.id).push(f) foundALayer = true if (!layer.layerDef.passAllFeatures) { @@ -67,7 +80,8 @@ export default class PerLayerFeatureSourceSplitter< // At this point, we have our features per layer as a list // We assign them to the correct featureSources - for (const layer of layers) { + for (let i = 0; i < layers.length; i++) { + const layer = layers[i] const id = layer.layerDef.id const features = featuresPerLayer.get(id) if (features === undefined) { @@ -75,14 +89,17 @@ export default class PerLayerFeatureSourceSplitter< continue } - const src = layerSources.get(id) - - if (Utils.sameList(src.data, features)) { + if (!hasChanged[i] && layerIndexes[i].size === newIndices[i].size) { + // No new id has been added and the sizes are the same (thus: nothing has been removed as well) + // We can safely assume that no changes were made continue } - src.setData(features) + + layerSources.get(id).setData(features) } + layerIndexes = newIndices + // AT last, the leftovers are handled if (options?.handleLeftovers !== undefined && noLayerFound.length > 0) { options.handleLeftovers(noLayerFound) @@ -90,7 +107,7 @@ export default class PerLayerFeatureSourceSplitter< }) } - public forEach(f: (featureSource: FeatureSourceForLayer) => void) { + public forEach(f: (featureSource: FeatureSource) => void) { for (const fs of this.perLayer.values()) { f(fs) } diff --git a/Logic/FeatureSource/Sources/OsmFeatureSource.ts b/Logic/FeatureSource/Sources/OsmFeatureSource.ts index 0c8949f7c..968f03d0b 100644 --- a/Logic/FeatureSource/Sources/OsmFeatureSource.ts +++ b/Logic/FeatureSource/Sources/OsmFeatureSource.ts @@ -122,7 +122,7 @@ export default class OsmFeatureSource extends FeatureSourceMerger { throw "This is an absurd high zoom level" } - if (z < 14) { + if (z < 15) { throw `Zoom ${z} is too much for OSM to handle! Use a higher zoom level!` } const index = Tiles.tile_index(z, x, y) diff --git a/Logic/MetaTagging.ts b/Logic/MetaTagging.ts index 15f10e4ab..5aa42c4ec 100644 --- a/Logic/MetaTagging.ts +++ b/Logic/MetaTagging.ts @@ -35,7 +35,18 @@ export default class MetaTagging { continue } const featureSource = state.perLayer.get(layer.id) - featureSource.features?.addCallbackAndRunD((features) => { + featureSource.features?.stabilized(1000)?.addCallbackAndRunD((features) => { + if (!(features?.length > 0)) { + // No features to handle + return + } + console.trace( + "Recalculating metatags for layer ", + layer.id, + "due to a change in the upstream features. Contains ", + features.length, + "items" + ) MetaTagging.addMetatags( features, params, @@ -71,7 +82,6 @@ export default class MetaTagging { return } - console.debug("Recalculating metatags...") const metatagsToApply: SimpleMetaTagger[] = [] for (const metatag of SimpleMetaTaggers.metatags) { if (metatag.includesDates) { diff --git a/Logic/State/LayerState.ts b/Logic/State/LayerState.ts index fc1f67135..96f63dd19 100644 --- a/Logic/State/LayerState.ts +++ b/Logic/State/LayerState.ts @@ -3,6 +3,8 @@ import { GlobalFilter } from "../../Models/GlobalFilter" import FilteredLayer from "../../Models/FilteredLayer" import LayerConfig from "../../Models/ThemeConfig/LayerConfig" import { OsmConnection } from "../Osm/OsmConnection" +import { Tag } from "../Tags/Tag" +import Translations from "../../UI/i18n/Translations" /** * The layer state keeps track of: @@ -41,6 +43,45 @@ export default class LayerState { } this.filteredLayers = filteredLayers layers.forEach((l) => LayerState.linkFilterStates(l, filteredLayers)) + + this.globalFilters.data.push({ + id: "level", + osmTags: undefined, + state: undefined, + onNewPoint: undefined, + }) + } + + /** + * Sets the global filter which looks to the 'level'-tag. + * Only features with the given 'level' will be shown. + * + * If undefined is passed, _all_ levels will be shown + * @param level + */ + public setLevelFilter(level?: string) { + // Remove all previous + const l = this.globalFilters.data.length + this.globalFilters.data = this.globalFilters.data.filter((f) => f.id !== "level") + if (!level) { + if (l !== this.globalFilters.data.length) { + this.globalFilters.ping() + } + return + } + const t = Translations.t.general.levelSelection + this.globalFilters.data.push({ + id: "level", + state: level, + osmTags: new Tag("level", level), + onNewPoint: { + tags: [new Tag("level", level)], + icon: "./assets/svg/elevator.svg", + confirmAddNew: t.confirmLevel.PartialSubs({ level }), + safetyCheck: t.addNewOnLevel.Subs({ level }), + }, + }) + this.globalFilters.ping() } /** diff --git a/Models/FilteredLayer.ts b/Models/FilteredLayer.ts index de9348536..ee07c2d50 100644 --- a/Models/FilteredLayer.ts +++ b/Models/FilteredLayer.ts @@ -186,6 +186,12 @@ export default class FilteredLayer { if (properties._deleted === "yes") { return false } + for (const globalFilter of globalFilters ?? []) { + const neededTags = globalFilter.osmTags + if (neededTags !== undefined && !neededTags.matchesProperties(properties)) { + return false + } + } { const isShown: TagsFilter = this.layerDef.isShown if (isShown !== undefined && !isShown.matchesProperties(properties)) { @@ -200,12 +206,6 @@ export default class FilteredLayer { } } - for (const globalFilter of globalFilters ?? []) { - const neededTags = globalFilter.osmTags - if (neededTags !== undefined && !neededTags.matchesProperties(properties)) { - return false - } - } return true } diff --git a/Models/GlobalFilter.ts b/Models/GlobalFilter.ts index 91750c7bd..ce837acca 100644 --- a/Models/GlobalFilter.ts +++ b/Models/GlobalFilter.ts @@ -8,6 +8,7 @@ export interface GlobalFilter { id: string onNewPoint: { safetyCheck: Translation + icon: string confirmAddNew: TypedTranslation<{ preset: Translation }> tags: Tag[] } diff --git a/Models/ThemeViewState.ts b/Models/ThemeViewState.ts index bad56a3bb..659683d2c 100644 --- a/Models/ThemeViewState.ts +++ b/Models/ThemeViewState.ts @@ -92,6 +92,10 @@ export default class ThemeViewState implements SpecialVisualizationState { string, { readonly isDisplayed: UIEventSource } > + /** + * All 'level'-tags that are available with the current features + */ + readonly floors: Store constructor(layout: LayoutConfig) { this.layout = layout @@ -214,17 +218,29 @@ export default class ThemeViewState implements SpecialVisualizationState { this.featureProperties ) + const doShowLayer = this.mapProperties.zoom.map( + (z) => + (fs.layer.isDisplayed?.data ?? true) && z >= (fs.layer.layerDef?.minzoom ?? 0), + [fs.layer.isDisplayed] + ) + + if ( + !doShowLayer.data && + (this.featureSwitches.featureSwitchFilter.data === false || !fs.layer.layerDef.name) + ) { + /* This layer is hidden and there is no way to enable it (filterview is disabled or this layer doesn't show up in the filter view as the name is not defined) + * + * This means that we don't have to filter it, nor do we have to display it + * */ + return + } + const filtered = new FilteringFeatureSource( fs.layer, fs, (id) => this.featureProperties.getStore(id), this.layerState.globalFilters ) - const doShowLayer = this.mapProperties.zoom.map( - (z) => - (fs.layer.isDisplayed?.data ?? true) && z >= (fs.layer.layerDef?.minzoom ?? 0), - [fs.layer.isDisplayed] - ) new ShowDataLayer(this.map, { layer: fs.layer.layerDef, @@ -236,6 +252,33 @@ export default class ThemeViewState implements SpecialVisualizationState { }) }) + this.floors = this.indexedFeatures.features.stabilized(500).map((features) => { + if (!features) { + return [] + } + const floors = new Set() + for (const feature of features) { + const level = feature.properties["level"] + if (level) { + floors.add(level) + } + } + const sorted = Array.from(floors) + // Sort alphabetically first, to deal with floor "A", "B" and "C" + sorted.sort() + sorted.sort((a, b) => { + // We use the laxer 'parseInt' to deal with floor '1A' + const na = parseInt(a) + const nb = parseInt(b) + if (isNaN(na) || isNaN(nb)) { + return 0 + } + return na - nb + }) + sorted.reverse(/* new list, no side-effects */) + return sorted + }) + const lastClick = (this.lastClickObject = new LastClickFeatureSource( this.mapProperties.lastClickLocation, this.layout @@ -443,7 +486,6 @@ export default class ThemeViewState implements SpecialVisualizationState { } const found = this.indexedFeatures.featuresById.data?.get(hash) - console.log("Found:", found) if (!found) { return } @@ -451,7 +493,7 @@ export default class ThemeViewState implements SpecialVisualizationState { this.selectedElement.setData(found) this.selectedLayer.setData(layer) }, - [this.indexedFeatures.featuresById] + [this.indexedFeatures.featuresById.stabilized(250)] ) new MetaTagging(this) diff --git a/UI/BigComponents/LevelSelector.svelte b/UI/BigComponents/LevelSelector.svelte new file mode 100644 index 000000000..68b29a71b --- /dev/null +++ b/UI/BigComponents/LevelSelector.svelte @@ -0,0 +1,29 @@ + +{#if $zoom >= maxZoom} + + {/if} diff --git a/UI/BigComponents/LevelSelector.ts b/UI/BigComponents/LevelSelector.ts deleted file mode 100644 index d40020f25..000000000 --- a/UI/BigComponents/LevelSelector.ts +++ /dev/null @@ -1,151 +0,0 @@ -import FloorLevelInputElement from "../Input/FloorLevelInputElement" -import MapState from "../../Logic/State/MapState" -import { TagsFilter } from "../../Logic/Tags/TagsFilter" -import { RegexTag } from "../../Logic/Tags/RegexTag" -import { Or } from "../../Logic/Tags/Or" -import { Tag } from "../../Logic/Tags/Tag" -import Translations from "../i18n/Translations" -import Combine from "../Base/Combine" -import { OsmFeature } from "../../Models/OsmFeature" -import { BBox } from "../../Logic/BBox" -import { TagUtils } from "../../Logic/Tags/TagUtils" -import FeaturePipeline from "../../Logic/FeatureSource/FeaturePipeline" -import { Store } from "../../Logic/UIEventSource" -import { GlobalFilter } from "../../Logic/State/GlobalFilter" - -/*** - * The element responsible for the level input element and picking the right level, showing and hiding at the right time, ... - */ -export default class LevelSelector extends Combine { - constructor(state: MapState & { featurePipeline: FeaturePipeline }) { - const levelsInView: Store> = state.currentBounds.map((bbox) => { - if (bbox === undefined) { - return {} - } - const allElementsUnfiltered: OsmFeature[] = [].concat( - ...state.featurePipeline.GetAllFeaturesAndMetaWithin(bbox).map((ff) => ff.features) - ) - const allElements = allElementsUnfiltered.filter((f) => BBox.get(f).overlapsWith(bbox)) - const allLevelsRaw: string[] = allElements.map((f) => f.properties["level"]) - - const levels: Record = { "0": 0 } - for (const levelDescription of allLevelsRaw) { - if (levelDescription === undefined) { - levels["0"]++ - } - for (const level of TagUtils.LevelsParser(levelDescription)) { - levels[level] = (levels[level] ?? 0) + 1 - } - } - - return levels - }) - - const levelSelect = new FloorLevelInputElement(levelsInView) - - state.globalFilters.data.push({ - filter: { - currentFilter: undefined, - state: undefined, - }, - id: "level", - onNewPoint: undefined, - }) - const isShown = levelsInView.map( - (levelsInView) => { - if (state.locationControl.data.zoom <= 16) { - return false - } - if (Object.keys(levelsInView).length == 1) { - return false - } - - return true - }, - [state.locationControl] - ) - - function setLevelFilter() { - console.log( - "Updating levels filter to ", - levelSelect.GetValue().data, - " is shown:", - isShown.data - ) - const filter: GlobalFilter = state.globalFilters.data.find((gf) => gf.id === "level") - if (!isShown.data) { - filter.filter = { - state: "*", - currentFilter: undefined, - } - filter.onNewPoint = undefined - state.globalFilters.ping() - return - } - - const l = levelSelect.GetValue().data - if (l === undefined) { - return - } - - let neededLevel: TagsFilter = new RegexTag("level", new RegExp("(^|;)" + l + "(;|$)")) - if (l === "0") { - neededLevel = new Or([neededLevel, new Tag("level", "")]) - } - filter.filter = { - state: l, - currentFilter: neededLevel, - } - const t = Translations.t.general.levelSelection - filter.onNewPoint = { - confirmAddNew: t.confirmLevel.PartialSubs({ level: l }), - safetyCheck: t.addNewOnLevel.Subs({ level: l }), - tags: [new Tag("level", l)], - } - state.globalFilters.ping() - return - } - - isShown.addCallbackAndRun((shown) => { - console.log("Is level selector shown?", shown) - setLevelFilter() - if (shown) { - levelSelect.RemoveClass("invisible") - } else { - levelSelect.SetClass("invisible") - } - }) - - levelsInView.addCallbackAndRun((levels) => { - if (!isShown.data) { - return - } - const value = levelSelect.GetValue() - if (!(levels[value.data] === undefined || levels[value.data] === 0)) { - return - } - // Nothing in view. Lets switch to a different level (the level with the most features) - let mostElements = 0 - let mostElementsLevel = undefined - for (const level in levels) { - const count = levels[level] - if (mostElementsLevel === undefined || mostElements < count) { - mostElementsLevel = level - mostElements = count - } - } - console.log( - "Force switching to a different level:", - mostElementsLevel, - "as it has", - mostElements, - "elements on that floor", - levels, - "(old level: " + value.data + ")" - ) - value.setData(mostElementsLevel) - }) - levelSelect.GetValue().addCallback((_) => setLevelFilter()) - super([levelSelect]) - } -} diff --git a/UI/BigComponents/RightControls.ts b/UI/BigComponents/RightControls.ts deleted file mode 100644 index 7c5280aba..000000000 --- a/UI/BigComponents/RightControls.ts +++ /dev/null @@ -1,11 +0,0 @@ -import Combine from "../Base/Combine" -import MapState from "../../Logic/State/MapState" -import LevelSelector from "./LevelSelector" - -export default class RightControls extends Combine { - constructor(state: MapState & { featurePipeline: FeaturePipeline }) { - const levelSelector = new LevelSelector(state) - super([levelSelector].map((el) => el.SetClass("m-0.5 md:m-1"))) - this.SetClass("flex flex-col items-center") - } -} diff --git a/UI/DefaultGUI.ts b/UI/DefaultGUI.ts index c5d08a8e7..24d943680 100644 --- a/UI/DefaultGUI.ts +++ b/UI/DefaultGUI.ts @@ -1,6 +1,5 @@ import Toggle from "./Input/Toggle" import LeftControls from "./BigComponents/LeftControls" -import RightControls from "./BigComponents/RightControls" import CenterMessageBox from "./CenterMessageBox" import { DefaultGuiState } from "./DefaultGuiState" import Combine from "./Base/Combine" @@ -42,7 +41,6 @@ export default class DefaultGUI { const guiState = this.guiState new LeftControls(state, guiState).AttachTo("bottom-left") - new RightControls(state, this.geolocationHandler).AttachTo("bottom-right") new CenterMessageBox(state).AttachTo("centermessage") document?.getElementById("centermessage")?.classList?.add("pointer-events-none") diff --git a/UI/InputElement/Helpers/FloorSelector.svelte b/UI/InputElement/Helpers/FloorSelector.svelte new file mode 100644 index 000000000..faa65eee2 --- /dev/null +++ b/UI/InputElement/Helpers/FloorSelector.svelte @@ -0,0 +1,140 @@ + + +
+
+ {#each $floors as floor, i} + + {/each} +
+ +
+ +
+
+ + + + diff --git a/UI/Popup/AddNewPoint/AddNewPoint.svelte b/UI/Popup/AddNewPoint/AddNewPoint.svelte index 1a31ba7a4..7904e6196 100644 --- a/UI/Popup/AddNewPoint/AddNewPoint.svelte +++ b/UI/Popup/AddNewPoint/AddNewPoint.svelte @@ -25,22 +25,36 @@ import { Tag } from "../../../Logic/Tags/Tag"; import type { WayId } from "../../../Models/OsmFeature"; import Loading from "../../Base/Loading.svelte"; + import type { GlobalFilter } from "../../../Models/GlobalFilter"; + import { onDestroy } from "svelte"; export let coordinate: { lon: number, lat: number }; export let state: SpecialVisualizationState; - let selectedPreset: { preset: PresetConfig, layer: LayerConfig, icon: string, tags: Record } = undefined; - + let selectedPreset: { + preset: PresetConfig, + layer: LayerConfig, + icon: string, + tags: Record + } = undefined; + let checkedOfGlobalFilters : number = 0 let confirmedCategory = false; $: if (selectedPreset === undefined) { confirmedCategory = false; creating = false; + checkedOfGlobalFilters = 0 + } let flayer: FilteredLayer = undefined; let layerIsDisplayed: UIEventSource | undefined = undefined; let layerHasFilters: Store | undefined = undefined; - + let globalFilter: UIEventSource = state.layerState.globalFilters; + let _globalFilter: GlobalFilter[]; + onDestroy(globalFilter.addCallbackAndRun(globalFilter => { + console.log("Global filters are", globalFilter); + _globalFilter = globalFilter ?? []; + })); $:{ flayer = state.layerState.filteredLayers.get(selectedPreset?.layer?.id); layerIsDisplayed = flayer?.isDisplayed; @@ -71,38 +85,38 @@ creating = true; const location: { lon: number; lat: number } = preciseCoordinate.data; const snapTo: WayId | undefined = snappedToObject.data; - const tags: Tag[] = selectedPreset.preset.tags; + const tags: Tag[] = selectedPreset.preset.tags.concat(..._globalFilter.map(f => f.onNewPoint.tags)); console.log("Creating new point at", location, "snapped to", snapTo, "with tags", tags); - let snapToWay: undefined | OsmWay = undefined - if(snapTo !== undefined){ + let snapToWay: undefined | OsmWay = undefined; + if (snapTo !== undefined) { const downloaded = await state.osmObjectDownloader.DownloadObjectAsync(snapTo, 0); - if(downloaded !== "deleted"){ - snapToWay = downloaded + if (downloaded !== "deleted") { + snapToWay = downloaded; } } const newElementAction = new CreateNewNodeAction(tags, location.lat, location.lon, { - theme: state.layout?.id ?? "unkown", - changeType: "create", - snapOnto: snapToWay - }); - await state.changes.applyAction(newElementAction) - state.newFeatures.features.ping() + theme: state.layout?.id ?? "unkown", + changeType: "create", + snapOnto: snapToWay + }); + await state.changes.applyAction(newElementAction); + state.newFeatures.features.ping(); // The 'changes' should have created a new point, which added this into the 'featureProperties' const newId = newElementAction.newElementId; - console.log("Applied pending changes, fetching store for", newId) + console.log("Applied pending changes, fetching store for", newId); const tagsStore = state.featureProperties.getStore(newId); { // Set some metainfo const properties = tagsStore.data; if (snapTo) { // metatags (starting with underscore) are not uploaded, so we can safely mark this - delete properties["_referencing_ways"] + delete properties["_referencing_ways"]; properties["_referencing_ways"] = `["${snapTo}"]`; } - properties["_backend"] = state.osmConnection.Backend() + properties["_backend"] = state.osmConnection.Backend(); properties["_last_edit:timestamp"] = new Date().toISOString(); const userdetails = state.osmConnection.userDetails.data; properties["_last_edit:contributor"] = userdetails.name; @@ -113,13 +127,17 @@ abort(); state.selectedLayer.setData(selectedPreset.layer); state.selectedElement.setData(feature); - tagsStore.ping() + tagsStore.ping(); } + @@ -163,7 +181,7 @@ {:else if $layerHasFilters} - +
@@ -231,6 +249,16 @@
+ {:else if _globalFilter.length > checkedOfGlobalFilters} + + {checkedOfGlobalFilters = checkedOfGlobalFilters + 1}}> + + + + {globalFilter.setData([]); abort()}}> + + + {:else if !creating} - public readonly restingQuestions: Store - constructor( state, options: { @@ -29,10 +26,6 @@ export default class QuestionBox extends VariableUiElement { const tagsSource = options.tagsSource const units = options.units - options.showAllQuestionsAtOnce = options.showAllQuestionsAtOnce ?? false - const tagRenderings = options.tagRenderings - .filter((tr) => tr.question !== undefined) - .filter((tr) => tr.question !== null) let focus: () => void = () => {} @@ -59,9 +52,6 @@ export default class QuestionBox extends VariableUiElement { ) ) - const skippedQuestionsButton = Translations.t.general.skippedQuestions.onClick(() => { - skippedQuestions.setData([]) - }) tagsSource.map( (tags) => { if (tags === undefined) { @@ -136,18 +126,12 @@ export default class QuestionBox extends VariableUiElement { els.push(allQuestions[0]) } - if (skippedQuestions.data.length > 0) { - els.push(skippedQuestionsButton) - } - return new Combine(els).SetClass("block mb-8") }, [state.osmConnection.apiIsOnline] ) ) - this.skippedQuestions = skippedQuestions - this.restingQuestions = questionsToAsk focus = () => this.ScrollIntoView() } } diff --git a/UI/Popup/TagRendering/Questionbox.svelte b/UI/Popup/TagRendering/Questionbox.svelte index b095c5df5..c8573ca84 100644 --- a/UI/Popup/TagRendering/Questionbox.svelte +++ b/UI/Popup/TagRendering/Questionbox.svelte @@ -72,6 +72,9 @@ let answered: number = 0; let skipped: number = 0; + function focus(){ + + } function skip(question: TagRenderingConfig, didAnswer: boolean = false) { skippedQuestions.data.add(question.id); skippedQuestions.ping(); diff --git a/UI/ThemeViewGUI.svelte b/UI/ThemeViewGUI.svelte index 55a61fdc5..d032edcbc 100644 --- a/UI/ThemeViewGUI.svelte +++ b/UI/ThemeViewGUI.svelte @@ -5,7 +5,6 @@ import FeatureSwitchState from "../Logic/State/FeatureSwitchState"; import MapControlButton from "./Base/MapControlButton.svelte"; import ToSvelte from "./Base/ToSvelte.svelte"; - import Svg from "../Svg"; import If from "./Base/If.svelte"; import { GeolocationControl } from "./BigComponents/GeolocationControl"; import type { Feature } from "geojson"; @@ -35,6 +34,7 @@ import { VariableUiElement } from "./Base/VariableUIElement"; import SvelteUIElement from "./Base/SvelteUIElement"; import OverlayToggle from "./BigComponents/OverlayToggle.svelte"; + import LevelSelector from "./BigComponents/LevelSelector.svelte"; export let state: ThemeViewState; let layout = state.layout; @@ -71,14 +71,14 @@
-
+
state.guistate.themeIsOpened.setData(true)}> -
+
@@ -101,7 +101,12 @@
-
+
+ f.length > 1)}> +
+ +
+
mapproperties.zoom.update(z => z+1)}> diff --git a/css/index-tailwind-output.css b/css/index-tailwind-output.css index 5684c978a..4ce129e4f 100644 --- a/css/index-tailwind-output.css +++ b/css/index-tailwind-output.css @@ -787,14 +787,14 @@ video { margin: 0.5rem; } -.m-4 { - margin: 1rem; -} - .m-1 { margin: 0.25rem; } +.m-4 { + margin: 1rem; +} + .m-6 { margin: 1.5rem; } @@ -857,10 +857,6 @@ video { margin-top: 0.25rem; } -.ml-1 { - margin-left: 0.25rem; -} - .mr-0\.5 { margin-right: 0.125rem; } @@ -885,6 +881,10 @@ video { margin-bottom: 6rem; } +.ml-1 { + margin-left: 0.25rem; +} + .ml-2 { margin-left: 0.5rem; } @@ -1146,6 +1146,11 @@ video { width: 12rem; } +.w-min { + width: -webkit-min-content; + width: min-content; +} + .w-auto { width: auto; } @@ -1260,6 +1265,10 @@ video { align-content: flex-start; } +.items-end { + align-items: flex-end; +} + .items-center { align-items: center; } @@ -2297,8 +2306,8 @@ input { color: var(--unsubtle-detail-color-contrast); } -@media (max-width: 320px) { - .max-\[320px\]\:w-full { +@media (max-width: 480px) { + .max-\[480px\]\:w-full { width: 100%; } } @@ -2322,6 +2331,10 @@ input { margin-right: auto; } + .sm\:mt-2 { + margin-top: 0.5rem; + } + .sm\:mr-1 { margin-right: 0.25rem; } @@ -2350,11 +2363,6 @@ input { width: 6rem; } - .sm\:w-min { - width: -webkit-min-content; - width: min-content; - } - .sm\:w-6 { width: 1.5rem; } @@ -2415,10 +2423,6 @@ input { margin: 0.25rem; } - .md\:m-4 { - margin: 1rem; - } - .md\:m-8 { margin: 2rem; } diff --git a/test.html b/test.html index 2a5d2478c..aece23274 100644 --- a/test.html +++ b/test.html @@ -17,7 +17,7 @@ -
'maindiv' not attached
+
'maindiv' not attached
'extradiv' not attached
diff --git a/test.ts b/test.ts index fd2294d46..f8863551a 100644 --- a/test.ts +++ b/test.ts @@ -5,12 +5,13 @@ import Combine from "./UI/Base/Combine" import SpecialVisualizations from "./UI/SpecialVisualizations" import InputHelpers from "./UI/InputElement/InputHelpers" import BaseUIElement from "./UI/BaseUIElement" -import { UIEventSource } from "./Logic/UIEventSource" +import { ImmutableStore, UIEventSource } from "./Logic/UIEventSource" import { VariableUiElement } from "./UI/Base/VariableUIElement" import { FixedUiElement } from "./UI/Base/FixedUiElement" import Title from "./UI/Base/Title" import SvelteUIElement from "./UI/Base/SvelteUIElement" import ValidatedInput from "./UI/InputElement/ValidatedInput.svelte" +import LevelSelector from "./UI/InputElement/Helpers/LevelSelector.svelte" function testspecial() { const layout = new LayoutConfig(theme, true) // qp.data === "" ? : new AllKnownLayoutsLazy().get(qp.data) @@ -47,7 +48,14 @@ function testinput() { new Combine(els).SetClass("flex flex-col").AttachTo("maindiv") } -testinput() +function testElevator() { + const floors = new ImmutableStore(["0", "1", "1.5", "2"]) + const value = new UIEventSource(undefined) + new SvelteUIElement(LevelSelector, { floors, value }).AttachTo("maindiv") + new VariableUiElement(value).AttachTo("extradiv") +} +testElevator() +//testinput() /*/ testspecial() //*/