MapComplete/src/UI/Studio/SchemaBasedArray.svelte

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

110 lines
3.3 KiB
Svelte
Raw Normal View History

2023-06-16 02:36:11 +02:00
<script lang="ts">
2023-08-08 13:52:58 +02:00
import EditLayerState from "./EditLayerState";
import type { ConfigMeta } from "./configMeta";
import { UIEventSource } from "../../Logic/UIEventSource";
import SchemaBasedInput from "./SchemaBasedInput.svelte";
import SchemaBasedField from "./SchemaBasedField.svelte";
import { TrashIcon } from "@babeard/svelte-heroicons/mini";
import TagRenderingInput from "./TagRenderingInput.svelte";
2023-08-08 13:52:58 +02:00
export let state: EditLayerState;
export let schema: ConfigMeta;
2023-06-20 01:32:24 +02:00
2023-08-08 13:52:58 +02:00
let title = schema.path.at(-1);
let singular = title;
if (title.endsWith("s")) {
singular = title.slice(0, title.length - 1);
}
let article = "a";
if (singular.match(/^[aeoui]/)) {
article = "an";
}
export let path: (string | number)[] = [];
2023-08-08 13:52:58 +02:00
const subparts = state.getSchemaStartingWith(schema.path);
2023-06-20 01:32:24 +02:00
2023-08-08 13:52:58 +02:00
/**
* Store the _indices_
*/
export let values: UIEventSource<number[]> = new UIEventSource<number[]>([]);
2023-08-08 13:52:58 +02:00
const currentValue = <[]>state.getCurrentValueFor(path);
if (currentValue) {
if (!Array.isArray(currentValue)) {
console.error("SchemaBaseArray for path", path, "expected an array as initial value, but got a", typeof currentValue, currentValue);
} else {
values.setData(currentValue.map((_, i) => i));
}
2023-08-08 13:52:58 +02:00
}
let createdItems = values.data.length;
2023-08-08 13:52:58 +02:00
function createItem() {
values.data.push(createdItems);
createdItems++;
values.ping();
}
2023-06-20 01:32:24 +02:00
2023-08-08 13:52:58 +02:00
function fusePath(i: number, subpartPath: string[]): (string | number)[] {
const newPath = [...path, i];
const toAdd = [...subpartPath];
for (const part of path) {
if (toAdd[0] === part) {
toAdd.splice(0, 1);
}
}
newPath.push(...toAdd);
return newPath;
}
2023-06-16 02:36:11 +02:00
2023-08-08 13:52:58 +02:00
function del(value) {
values.data.splice(values.data.indexOf(value));
values.ping();
}
2023-08-08 13:52:58 +02:00
</script>
<div class="pl-2">
2023-08-08 13:52:58 +02:00
<h3>{schema.path.at(-1)}</h3>
2023-08-08 13:52:58 +02:00
{#if subparts.length > 0}
2023-06-20 01:32:24 +02:00
<span class="subtle">
{schema.description}
</span>
2023-08-08 13:52:58 +02:00
{/if}
2023-08-08 13:52:58 +02:00
{#if $values.length === 0}
No values are defined
{:else if subparts.length === 0}
<!-- We need an array of values, so we use the typehint of the _parent_ element as field -->
{#each $values as value (value)}
<div class="flex w-full">
<SchemaBasedField {state} {schema} path={[...path, value]} />
<button class="border-black border rounded-full p-1 w-fit h-fit"
on:click={() => {del(value)}}>
<TrashIcon class="w-4 h-4" />
</button>
</div>
{/each}
{:else}
{#each $values as value (value)}
<div class="flex justify-between items-center">
<h3 class="m-0">{singular} {value}</h3>
<button class="border-black border rounded-full p-1 w-fit h-fit"
on:click={() => {del(value)}}>
<TrashIcon class="w-4 h-4" />
</button>
</div>
<div class="border border-black">
{#if path.length === 1 && path[0] === "tagRenderings"}
<TagRenderingInput path={path.concat(value)} {state} {schema}/>
{:else}
{#each subparts as subpart}
<SchemaBasedInput {state} path={fusePath(value, subpart.path)} schema={subpart} />
{/each}
{/if}
</div>
{/each}
{/if}
<button on:click={createItem}>Add {article} {singular}</button>
</div>