feat(frontend): fields editor
This commit is contained in:
parent
7c52ab759c
commit
f435ad4cf5
7 changed files with 319 additions and 166 deletions
|
@ -2,14 +2,25 @@
|
|||
import type { CustomPreference, FieldEntry } from "$api/models";
|
||||
import IconButton from "$components/IconButton.svelte";
|
||||
import { t } from "$lib/i18n";
|
||||
import { InputGroup, InputGroupText } from "@sveltestrap/sveltestrap";
|
||||
import FieldEntryEditor from "./FieldEntryEditor.svelte";
|
||||
|
||||
type Props = {
|
||||
name: string;
|
||||
entries: FieldEntry[];
|
||||
allPreferences: Record<string, CustomPreference>;
|
||||
index?: number;
|
||||
move?: (index: number, up: boolean) => void;
|
||||
remove?: (index: number) => void;
|
||||
};
|
||||
let { name, entries = $bindable(), allPreferences }: Props = $props();
|
||||
let {
|
||||
name = $bindable(),
|
||||
entries = $bindable(),
|
||||
allPreferences,
|
||||
index,
|
||||
move,
|
||||
remove,
|
||||
}: Props = $props();
|
||||
|
||||
let newEntry = $state("");
|
||||
|
||||
|
@ -38,19 +49,45 @@
|
|||
};
|
||||
</script>
|
||||
|
||||
<h4>{name}</h4>
|
||||
{#if index !== undefined && move && remove}
|
||||
<div class="d-flex">
|
||||
<InputGroup>
|
||||
<IconButton
|
||||
icon="chevron-up"
|
||||
color="secondary"
|
||||
tooltip={$t("editor.move-field-up")}
|
||||
onclick={() => move(index, true)}
|
||||
/>
|
||||
<IconButton
|
||||
icon="chevron-down"
|
||||
color="secondary"
|
||||
tooltip={$t("editor.move-field-down")}
|
||||
onclick={() => move(index, false)}
|
||||
/>
|
||||
<InputGroupText>{$t("editor.field-name")}</InputGroupText>
|
||||
<input class="form-control" bind:value={name} />
|
||||
<IconButton
|
||||
color="danger"
|
||||
icon="trash3"
|
||||
tooltip={$t("editor.remove-field")}
|
||||
onclick={() => remove(index)}
|
||||
/>
|
||||
</InputGroup>
|
||||
</div>
|
||||
{:else}
|
||||
<h4>{name}</h4>
|
||||
{/if}
|
||||
|
||||
{#each entries as _, index}
|
||||
<FieldEntryEditor
|
||||
{index}
|
||||
bind:value={entries[index]}
|
||||
{allPreferences}
|
||||
{moveValue}
|
||||
{removeValue}
|
||||
/>
|
||||
{#each entries as _, i}
|
||||
<FieldEntryEditor index={i} bind:value={entries[i]} {allPreferences} {moveValue} {removeValue} />
|
||||
{/each}
|
||||
|
||||
<form class="input-group m-1" onsubmit={addEntry}>
|
||||
<input type="text" class="form-control" bind:value={newEntry} />
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
bind:value={newEntry}
|
||||
placeholder={$t("editor.new-entry")}
|
||||
/>
|
||||
<IconButton type="submit" color="success" icon="plus" tooltip={$t("editor.add-entry")} />
|
||||
</form>
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
icon="chevron-down"
|
||||
color="secondary"
|
||||
tooltip={$t("editor.move-entry-down")}
|
||||
onclick={() => moveValue(index, true)}
|
||||
onclick={() => moveValue(index, false)}
|
||||
/>
|
||||
<input type="text" class="form-control" bind:value={value.value} />
|
||||
<ButtonDropdown>
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
<script lang="ts">
|
||||
import type { RawApiError } from "$api/error";
|
||||
import type { CustomPreference, Field } from "$api/models";
|
||||
import IconButton from "$components/IconButton.svelte";
|
||||
import { t } from "$lib/i18n";
|
||||
import FieldEditor from "./FieldEditor.svelte";
|
||||
import FormStatusMarker from "./FormStatusMarker.svelte";
|
||||
import NoscriptWarning from "./NoscriptWarning.svelte";
|
||||
|
||||
type Props = {
|
||||
fields: Field[];
|
||||
ok: { ok: boolean; error: RawApiError | null } | null;
|
||||
allPreferences: Record<string, CustomPreference>;
|
||||
update: () => Promise<void>;
|
||||
};
|
||||
|
||||
let { fields = $bindable(), ok, allPreferences, update }: Props = $props();
|
||||
|
||||
let newFieldName = $state("");
|
||||
|
||||
const moveField = (index: number, up: boolean) => {
|
||||
if (up && index == 0) return;
|
||||
if (!up && index == fields.length - 1) return;
|
||||
|
||||
const newIndex = up ? index - 1 : index + 1;
|
||||
const temp = fields[index];
|
||||
fields[index] = fields[newIndex];
|
||||
fields[newIndex] = temp;
|
||||
fields = [...fields];
|
||||
};
|
||||
|
||||
const removeField = (index: number) => {
|
||||
fields.splice(index, 1);
|
||||
fields = [...fields];
|
||||
};
|
||||
|
||||
const addField = (event: Event) => {
|
||||
event.preventDefault();
|
||||
if (!newFieldName) return;
|
||||
|
||||
fields = [...fields, { name: newFieldName, entries: [] }];
|
||||
newFieldName = "";
|
||||
};
|
||||
</script>
|
||||
|
||||
<NoscriptWarning />
|
||||
<FormStatusMarker form={ok} />
|
||||
|
||||
<h4>{$t("edit-profile.editing-fields-header")}</h4>
|
||||
|
||||
<div>
|
||||
<h5>{$t("editor.add-field")}</h5>
|
||||
<form class="input-group m-1" onsubmit={addField}>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
bind:value={newFieldName}
|
||||
placeholder={$t("editor.field-name")}
|
||||
/>
|
||||
<IconButton type="submit" color="success" icon="plus" tooltip={$t("editor.add-field")} />
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{#if fields.length > 0}
|
||||
<hr />
|
||||
{#each fields as field, index}
|
||||
<FieldEditor
|
||||
{index}
|
||||
bind:name={field.name}
|
||||
bind:entries={field.entries}
|
||||
{allPreferences}
|
||||
move={moveField}
|
||||
remove={removeField}
|
||||
/>
|
||||
{/each}
|
||||
{/if}
|
||||
<div>
|
||||
<button class="btn btn-primary" onclick={() => update()}>{$t("save-changes")}</button>
|
||||
</div>
|
Loading…
Add table
Add a link
Reference in a new issue