forked from MapComplete/MapComplete
Refactoring: refactoring of all Conversions
This commit is contained in:
parent
4e8dfc0026
commit
f2863cdf17
38 changed files with 1177 additions and 1269 deletions
41
src/UI/Map/DynamicIcon.svelte
Normal file
41
src/UI/Map/DynamicIcon.svelte
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<script lang="ts">
|
||||
import { IconConfig } from "../../Models/ThemeConfig/PointRenderingConfig";
|
||||
import { Store } from "../../Logic/UIEventSource";
|
||||
import Pin from "../../assets/svg/Pin.svelte";
|
||||
import Square from "../../assets/svg/Square.svelte";
|
||||
import Circle from "../../assets/svg/Circle.svelte";
|
||||
import Checkmark from "../../assets/svg/Checkmark.svelte";
|
||||
import Clock from "../../assets/svg/Clock.svelte";
|
||||
import Close from "../../assets/svg/Close.svelte";
|
||||
import Crosshair from "../../assets/svg/Crosshair.svelte";
|
||||
import Help from "../../assets/svg/Help.svelte";
|
||||
import Home from "../../assets/svg/Home.svelte";
|
||||
import Invalid from "../../assets/svg/Invalid.svelte";
|
||||
import Location from "../../assets/svg/Location.svelte";
|
||||
import Location_empty from "../../assets/svg/Location_empty.svelte";
|
||||
import Location_locked from "../../assets/svg/Location_locked.svelte";
|
||||
import Note from "../../assets/svg/Note.svelte";
|
||||
import Resolved from "../../assets/svg/Resolved.svelte";
|
||||
import Ring from "../../assets/svg/Ring.svelte";
|
||||
import Scissors from "../../assets/svg/Scissors.svelte";
|
||||
import Teardrop from "../../assets/svg/Teardrop.svelte";
|
||||
import Teardrop_with_hole_green from "../../assets/svg/Teardrop_with_hole_green.svelte";
|
||||
import Triangle from "../../assets/svg/Triangle.svelte";
|
||||
import Icon from "./Icon.svelte";
|
||||
|
||||
/**
|
||||
* Renders a single icon.
|
||||
*
|
||||
* Icons -placed on top of each other- form a 'Marker' together
|
||||
*/
|
||||
export let icon: IconConfig;
|
||||
export let tags: Store<Record<string, string>>;
|
||||
|
||||
let iconItem = icon.icon?.GetRenderValue(tags)?.txt;
|
||||
$: iconItem = icon.icon?.GetRenderValue($tags)?.txt;
|
||||
let color = icon.color?.GetRenderValue(tags)?.txt ?? "#000000";
|
||||
$: color = icon.color?.GetRenderValue($tags)?.txt ?? "#000000";
|
||||
|
||||
</script>
|
||||
|
||||
<Icon icon={iconItem} {color}/>
|
||||
21
src/UI/Map/DynamicMarker.svelte
Normal file
21
src/UI/Map/DynamicMarker.svelte
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<script lang="ts">
|
||||
|
||||
import PointRenderingConfig, { IconConfig } from "../../Models/ThemeConfig/PointRenderingConfig";
|
||||
import { Store } from "../../Logic/UIEventSource";
|
||||
import DynamicIcon from "./DynamicIcon.svelte";
|
||||
|
||||
/**
|
||||
* Renders a 'marker', which consists of multiple 'icons'
|
||||
*/
|
||||
export let config: PointRenderingConfig;
|
||||
let icons: IconConfig[] = config.marker;
|
||||
export let tags: Store<Record<string, string>>;
|
||||
|
||||
</script>
|
||||
{#if config !== undefined}
|
||||
<div class="relative w-full h-full">
|
||||
{#each icons as icon}
|
||||
<DynamicIcon {icon} {tags} />
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
|
@ -1,6 +1,4 @@
|
|||
<script lang="ts">
|
||||
import { IconConfig } from "../../Models/ThemeConfig/PointRenderingConfig";
|
||||
import { Store } from "../../Logic/UIEventSource";
|
||||
import Pin from "../../assets/svg/Pin.svelte";
|
||||
import Square from "../../assets/svg/Square.svelte";
|
||||
import Circle from "../../assets/svg/Circle.svelte";
|
||||
|
|
@ -27,60 +25,56 @@
|
|||
*
|
||||
* Icons -placed on top of each other- form a 'Marker' together
|
||||
*/
|
||||
export let icon: IconConfig;
|
||||
export let tags: Store<Record<string, string>>;
|
||||
|
||||
let iconItem = icon.icon?.GetRenderValue(tags)?.txt;
|
||||
$: iconItem = icon.icon?.GetRenderValue($tags)?.txt;
|
||||
let color = icon.color?.GetRenderValue(tags)?.txt ?? "#000000";
|
||||
$: color = icon.color?.GetRenderValue($tags)?.txt ?? "#000000";
|
||||
export let icon: string | undefined;
|
||||
export let color: string | undefined;
|
||||
|
||||
</script>
|
||||
|
||||
{#if iconItem}
|
||||
{#if icon}
|
||||
<div class="absolute top-0 left-0 w-full h-full">
|
||||
{#if iconItem === "pin"}
|
||||
{#if icon === "pin"}
|
||||
<Pin {color} />
|
||||
{:else if iconItem === "square"}
|
||||
{:else if icon === "square"}
|
||||
<Square {color} />
|
||||
{:else if iconItem === "circle"}
|
||||
{:else if icon === "circle"}
|
||||
<Circle {color} />
|
||||
{:else if iconItem === "checkmark"}
|
||||
{:else if icon === "checkmark"}
|
||||
<Checkmark {color} />
|
||||
{:else if iconItem === "clock"}
|
||||
{:else if icon === "clock"}
|
||||
<Clock {color} />
|
||||
{:else if iconItem === "close"}
|
||||
{:else if icon === "close"}
|
||||
<Close {color} />
|
||||
{:else if iconItem === "crosshair"}
|
||||
{:else if icon === "crosshair"}
|
||||
<Crosshair {color} />
|
||||
{:else if iconItem === "help"}
|
||||
{:else if icon === "help"}
|
||||
<Help {color} />
|
||||
{:else if iconItem === "home"}
|
||||
{:else if icon === "home"}
|
||||
<Home {color} />
|
||||
{:else if iconItem === "invalid"}
|
||||
{:else if icon === "invalid"}
|
||||
<Invalid {color} />
|
||||
{:else if iconItem === "location"}
|
||||
{:else if icon === "location"}
|
||||
<Location {color} />
|
||||
{:else if iconItem === "location_empty"}
|
||||
{:else if icon === "location_empty"}
|
||||
<Location_empty {color} />
|
||||
{:else if iconItem === "location_locked"}
|
||||
{:else if icon === "location_locked"}
|
||||
<Location_locked {color} />
|
||||
{:else if iconItem === "note"}
|
||||
{:else if icon === "note"}
|
||||
<Note {color} />
|
||||
{:else if iconItem === "resolved"}
|
||||
{:else if icon === "resolved"}
|
||||
<Resolved {color} />
|
||||
{:else if iconItem === "ring"}
|
||||
{:else if icon === "ring"}
|
||||
<Ring {color} />
|
||||
{:else if iconItem === "scissors"}
|
||||
{:else if icon === "scissors"}
|
||||
<Scissors {color} />
|
||||
{:else if iconItem === "teardrop"}
|
||||
{:else if icon === "teardrop"}
|
||||
<Teardrop {color} />
|
||||
{:else if iconItem === "teardrop_with_hole_green"}
|
||||
{:else if icon === "teardrop_with_hole_green"}
|
||||
<Teardrop_with_hole_green {color} />
|
||||
{:else if iconItem === "triangle"}
|
||||
{:else if icon === "triangle"}
|
||||
<Triangle {color} />
|
||||
{:else}
|
||||
<img class="w-full h-full" src={iconItem} />
|
||||
<img class="w-full h-full" src={icon} />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,17 @@
|
|||
<script lang="ts">
|
||||
|
||||
import PointRenderingConfig, { IconConfig } from "../../Models/ThemeConfig/PointRenderingConfig";
|
||||
import Icon from "./Icon.svelte";
|
||||
import { Store } from "../../Logic/UIEventSource";
|
||||
|
||||
/**
|
||||
* Renders a 'marker', which consists of multiple 'icons'
|
||||
*/
|
||||
export let config: PointRenderingConfig;
|
||||
let icons: IconConfig[] = config.marker;
|
||||
export let tags: Store<Record<string, string>>;
|
||||
export let icons: { icon: string, color: string }[]
|
||||
|
||||
</script>
|
||||
{#if config !== undefined}
|
||||
{#if icons !== undefined && icons.length > 0}
|
||||
<div class="relative w-full h-full">
|
||||
{#each icons as icon}
|
||||
<Icon {icon} {tags} />
|
||||
<Icon icon={icon.icon} color={icon.color} />
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -235,6 +235,7 @@
|
|||
bind:group={selectedMapping}
|
||||
name={"mappings-radio-" + config.id}
|
||||
value={i}
|
||||
on:keypress={e => {console.log(e) ; if(e.key === "Enter") onSave()}}
|
||||
/>
|
||||
</TagRenderingMappingInput>
|
||||
{/each}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
* Blacklist of regions for the general area tab
|
||||
* These are regions which are handled by a different tab
|
||||
*/
|
||||
const regionBlacklist = ["hidden", undefined, "infobox", "tagrenderings", "maprendering", "editing", "title"];
|
||||
const regionBlacklist = ["hidden", undefined, "infobox", "tagrenderings", "maprendering", "editing", "title","linerendering","pointrendering"];
|
||||
const allNames = Utils.Dedup(layerSchema.map(meta => meta.hints.group));
|
||||
|
||||
const perRegion: Record<string, ConfigMeta[]> = {};
|
||||
|
|
@ -27,7 +27,7 @@
|
|||
perRegion[region] = layerSchema.filter(meta => meta.hints.group === region);
|
||||
}
|
||||
|
||||
const baselayerRegions: string[] = ["Basic", "presets", "filters", "advanced", "expert"];
|
||||
const baselayerRegions: string[] = ["Basic", "presets", "filters"];
|
||||
for (const baselayerRegion of baselayerRegions) {
|
||||
if (perRegion[baselayerRegion] === undefined) {
|
||||
console.error("BaseLayerRegions in editLayer: no items have group '" + baselayerRegion + "\"");
|
||||
|
|
@ -38,8 +38,6 @@
|
|||
</script>
|
||||
|
||||
<h3>Editing layer {$title}</h3>
|
||||
<h4>Leftover regions</h4>
|
||||
{leftoverRegions.join("; ")}
|
||||
<div class="m4">
|
||||
<TabbedGroup tab={new UIEventSource(2)}>
|
||||
<div slot="title0">General properties</div>
|
||||
|
|
@ -47,9 +45,6 @@
|
|||
{#each baselayerRegions as region}
|
||||
<Region {state} configs={perRegion[region]} title={region} />
|
||||
{/each}
|
||||
{#each leftoverRegions as region}
|
||||
<Region {state} configs={perRegion[region]} title={region} />
|
||||
{/each}
|
||||
</div>
|
||||
<div slot="title1">Information panel (questions and answers)</div>
|
||||
<div slot="content1">
|
||||
|
|
@ -63,8 +58,14 @@
|
|||
<Region configs={perRegion["linerendering"]} {state} />
|
||||
<Region configs={perRegion["pointrendering"]} {state} />
|
||||
</div>
|
||||
<div slot="title3">Configuration file</div>
|
||||
|
||||
<div slot="title3">Advanced functionality</div>
|
||||
<div slot="content3">
|
||||
<Region configs={perRegion["advanced"]} {state} />
|
||||
<Region configs={perRegion["expert"]} {state} />
|
||||
</div>
|
||||
<div slot="title4">Configuration file</div>
|
||||
<div slot="content4">
|
||||
<div>
|
||||
Below, you'll find the raw configuration file in `.json`-format.
|
||||
This is mostly for debugging purposes
|
||||
|
|
|
|||
|
|
@ -65,8 +65,13 @@ console.log("For ", schema.path, "got subparts", subparts)
|
|||
}
|
||||
|
||||
function del(value) {
|
||||
values.data.splice(values.data.indexOf(value));
|
||||
const index = values.data.indexOf(value)
|
||||
console.log("Deleting",value, index)
|
||||
values.data.splice(index, 1);
|
||||
const store = <UIEventSource<[]>>state.getStoreFor(path);
|
||||
store.data.splice(index, 1)
|
||||
values.ping();
|
||||
store.ping()
|
||||
}
|
||||
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -96,13 +96,13 @@
|
|||
err = path.join(".") + " " + e
|
||||
}
|
||||
let startValue = state.getCurrentValueFor(path)
|
||||
if (typeof startValue !== "string") {
|
||||
startValue = JSON.stringify(startValue)
|
||||
}
|
||||
const tags = new UIEventSource<Record<string, string>>({value: startValue ?? ""})
|
||||
try {
|
||||
onDestroy(state.register(path, tags.map(tgs => {
|
||||
const v = tgs["value"];
|
||||
if(typeof v !== "string"){
|
||||
return v
|
||||
}
|
||||
if (schema.type === "boolan") {
|
||||
return v === "true" || v === "yes" || v === "1"
|
||||
}
|
||||
|
|
@ -135,7 +135,6 @@
|
|||
<span class="alert">{err}</span>
|
||||
{:else}
|
||||
<div class="w-full flex flex-col">
|
||||
<span class="subtle">{path.join(".")}</span>
|
||||
<TagRenderingEditable {config} selectedElement={undefined} showQuestionIfUnknown={true} {state} {tags}/>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -214,5 +214,4 @@
|
|||
path={[...subpath, (subschema?.path?.at(-1) ?? "???")]}></SchemaBasedInput>
|
||||
{/each}
|
||||
{/if}
|
||||
{chosenOption}
|
||||
</div>
|
||||
|
|
|
|||
38
src/UI/Studio/StudioServer.ts
Normal file
38
src/UI/Studio/StudioServer.ts
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import { Utils } from "../../Utils"
|
||||
import Constants from "../../Models/Constants"
|
||||
import { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson"
|
||||
|
||||
export default class StudioServer {
|
||||
private _url: string
|
||||
|
||||
constructor(url: string) {
|
||||
this._url = url
|
||||
}
|
||||
|
||||
public async fetchLayerOverview(): Promise<Set<string>> {
|
||||
const { allFiles } = <{ allFiles: string[] }>(
|
||||
await Utils.downloadJson(this._url + "/overview")
|
||||
)
|
||||
const layers = allFiles
|
||||
.filter((f) => f.startsWith("layers/"))
|
||||
.map((l) => l.substring(l.lastIndexOf("/") + 1, l.length - ".json".length))
|
||||
.filter((layerId) => Constants.priviliged_layers.indexOf(<any>layerId) < 0)
|
||||
return new Set<string>(layers)
|
||||
}
|
||||
|
||||
async fetchLayer(layerId: string, checkNew: boolean = false): Promise<LayerConfigJson> {
|
||||
try {
|
||||
return await Utils.downloadJson(
|
||||
this._url +
|
||||
"/layers/" +
|
||||
layerId +
|
||||
"/" +
|
||||
layerId +
|
||||
".json" +
|
||||
(checkNew ? ".new.json" : "")
|
||||
)
|
||||
} catch (e) {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,35 +2,32 @@
|
|||
|
||||
|
||||
import NextButton from "./Base/NextButton.svelte";
|
||||
import { Utils } from "../Utils";
|
||||
import { UIEventSource } from "../Logic/UIEventSource";
|
||||
import Constants from "../Models/Constants";
|
||||
import ValidatedInput from "./InputElement/ValidatedInput.svelte";
|
||||
import EditLayerState from "./Studio/EditLayerState";
|
||||
import EditLayer from "./Studio/EditLayer.svelte";
|
||||
import Loading from "../assets/svg/Loading.svelte";
|
||||
import Marker from "./Map/Marker.svelte";
|
||||
import { AllSharedLayers } from "../Customizations/AllSharedLayers";
|
||||
import StudioServer from "./Studio/StudioServer";
|
||||
import LoginToggle from "./Base/LoginToggle.svelte";
|
||||
import { OsmConnection } from "../Logic/Osm/OsmConnection";
|
||||
import { QueryParameters } from "../Logic/Web/QueryParameters";
|
||||
|
||||
|
||||
export let studioUrl = "http://127.0.0.1:1235";
|
||||
let overview = UIEventSource.FromPromise<{ allFiles: string[] }>(Utils.downloadJson(studioUrl + "/overview"));
|
||||
let layers = overview.map(overview => {
|
||||
if (!overview) {
|
||||
return [];
|
||||
}
|
||||
return overview.allFiles.filter(f => f.startsWith("layers/")
|
||||
).map(l => l.substring(l.lastIndexOf("/") + 1, l.length - ".json".length))
|
||||
.filter(layerId => Constants.priviliged_layers.indexOf(layerId) < 0);
|
||||
});
|
||||
const studio = new StudioServer(studioUrl);
|
||||
let layers = UIEventSource.FromPromise(studio.fetchLayerOverview());
|
||||
let state: undefined | "edit_layer" | "new_layer" | "edit_theme" | "new_theme" | "editing_layer" | "loading" = undefined;
|
||||
|
||||
let initialLayerConfig: undefined;
|
||||
let initialLayerConfig: { id: string };
|
||||
let newLayerId = new UIEventSource<string>("");
|
||||
let layerIdFeedback = new UIEventSource<string>(undefined);
|
||||
newLayerId.addCallbackD(layerId => {
|
||||
if (layerId === "") {
|
||||
return;
|
||||
}
|
||||
if (layers.data.indexOf(layerId) >= 0) {
|
||||
if (layers.data.has(layerId)) {
|
||||
layerIdFeedback.setData("This id is already used");
|
||||
}
|
||||
}, [layers]);
|
||||
|
|
@ -38,7 +35,28 @@
|
|||
|
||||
let editLayerState = new EditLayerState();
|
||||
|
||||
function fetchIconDescription(layerId): any {
|
||||
const icon = AllSharedLayers.getSharedLayersConfigs().get(layerId)?._layerIcon;
|
||||
console.log(icon);
|
||||
return icon;
|
||||
}
|
||||
|
||||
let osmConnection = new OsmConnection( new OsmConnection({
|
||||
oauth_token: QueryParameters.GetQueryParameter(
|
||||
"oauth_token",
|
||||
undefined,
|
||||
"Used to complete the login"
|
||||
),
|
||||
}))
|
||||
|
||||
</script>
|
||||
|
||||
<LoginToggle state={{osmConnection}}>
|
||||
<div slot="not-logged-in" >
|
||||
<NextButton clss="primary">
|
||||
Please log in to use MapComplete Studio
|
||||
</NextButton>
|
||||
</div>
|
||||
{#if state === undefined}
|
||||
<h1>MapComplete Studio</h1>
|
||||
<div class="w-full flex flex-col">
|
||||
|
|
@ -58,13 +76,16 @@
|
|||
</div>
|
||||
{:else if state === "edit_layer"}
|
||||
<div class="flex flex-wrap">
|
||||
{#each $layers as layerId}
|
||||
{#each Array.from($layers) as layerId}
|
||||
<NextButton clss="small" on:click={async () => {
|
||||
console.log("Editing layer",layerId)
|
||||
state = "loading"
|
||||
initialLayerConfig = await Utils.downloadJson(studioUrl+"/layers/"+layerId+"/"+layerId+".json")
|
||||
initialLayerConfig = await studio.fetchLayer(layerId)
|
||||
state = "editing_layer"
|
||||
}}>
|
||||
<div class="w-4 h-4 mr-1">
|
||||
<Marker icons={fetchIconDescription(layerId)} />
|
||||
</div>
|
||||
{layerId}
|
||||
</NextButton>
|
||||
{/each}
|
||||
|
|
@ -76,12 +97,22 @@
|
|||
{$layerIdFeedback}
|
||||
</div>
|
||||
{:else }
|
||||
<NextButton on:click={() => {initialLayerConfig = ({id: newLayerId.data}); state = "editing_layer"}}>
|
||||
<NextButton on:click={async () => {
|
||||
state = "loading"
|
||||
const id = newLayerId.data
|
||||
const createdBy = osmConnection.userDetails.data.name
|
||||
|
||||
const loaded = await studio.fetchLayer(id, true)
|
||||
initialLayerConfig = loaded ?? {id, credits: createdBy};
|
||||
state = "editing_layer"}}>
|
||||
Create this layer
|
||||
</NextButton>
|
||||
{/if}
|
||||
{:else if state === "loading"}
|
||||
<Loading />
|
||||
<div class="w-8 h-8">
|
||||
<Loading />
|
||||
</div>
|
||||
{:else if state === "editing_layer"}
|
||||
<EditLayer {initialLayerConfig} />
|
||||
{/if}
|
||||
</LoginToggle>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue