phonograph/svelte/src/field-header.svelte

149 lines
4.3 KiB
Svelte
Raw Normal View History

2025-08-13 18:52:37 -07:00
<script lang="ts">
2025-10-25 05:32:22 +00:00
import BasicDropdown from "./basic-dropdown.webc.svelte";
2025-08-13 18:52:37 -07:00
import { type FieldInfo } from "./field.svelte";
2025-09-08 15:56:57 -07:00
import FieldDetails from "./field-details.svelte";
2025-08-13 18:52:37 -07:00
type Props = {
field: FieldInfo;
index: number;
2025-11-05 22:48:55 +00:00
ondragenter?(ev: DragEvent): unknown;
ondragleave?(ev: DragEvent): unknown;
ondragover?(ev: DragEvent): unknown;
ondragstart?(ev: DragEvent): unknown;
ondrop?(ev: DragEvent): unknown;
2025-08-13 18:52:37 -07:00
};
2025-11-05 22:48:55 +00:00
let {
field = $bindable(),
index,
ondragenter,
ondragleave,
ondragover,
ondragstart,
ondrop,
}: Props = $props();
2025-09-08 15:56:57 -07:00
const original_label_value = field.field.table_label;
2025-09-08 15:56:57 -07:00
let type_indicator_element = $state<HTMLButtonElement | undefined>();
2025-11-12 23:00:30 +00:00
let remove_field_dialog_element = $state<HTMLDialogElement | undefined>();
let field_config_dialog_element = $state<HTMLDialogElement | undefined>();
2025-09-08 15:56:57 -07:00
let name_value = $state(field.field.name);
let label_value = $state(field.field.table_label ?? "");
2025-09-08 15:56:57 -07:00
$effect(() => {
field.field.table_label = label_value === "" ? undefined : label_value;
2025-09-08 15:56:57 -07:00
});
2025-08-13 18:52:37 -07:00
</script>
<div
aria-colindex={index}
2025-09-08 15:56:57 -07:00
class="field-header__container"
2025-11-05 22:48:55 +00:00
draggable={true}
{ondragenter}
{ondragleave}
{ondragover}
{ondragstart}
{ondrop}
2025-08-13 18:52:37 -07:00
role="columnheader"
style:width={`${field.field.table_width_px}px`}
2025-11-05 22:48:55 +00:00
tabindex={0}
2025-08-13 18:52:37 -07:00
>
2025-09-08 15:56:57 -07:00
<div class="field-header__label">
{field.field.table_label ?? field.field.name}
2025-09-08 15:56:57 -07:00
</div>
<div class="field-header__menu-container">
2025-10-25 05:32:22 +00:00
<BasicDropdown
alignment="right"
2025-11-12 23:00:30 +00:00
button_aria_label="Field options"
2025-10-25 05:32:22 +00:00
button_class="field-header__type-indicator"
on_toggle={(ev) => {
if (ev.newState === "closed") {
type_indicator_element?.focus();
field.field.table_label = original_label_value;
label_value = original_label_value ?? "";
}
}}
2025-09-08 15:56:57 -07:00
>
2025-10-25 05:32:22 +00:00
<span slot="button-contents">
{#if field.field.presentation.t === "Dropdown"}
2025-11-12 23:00:30 +00:00
<i class="ti ti-select"></i>
2025-11-11 01:26:48 +00:00
{:else if field.field.presentation.t === "Numeric"}
<i class="ti ti-decimal"></i>
2025-10-25 05:32:22 +00:00
{:else if field.field.presentation.t === "Text"}
<i class="ti ti-file-text"></i>
{:else if field.field.presentation.t === "Timestamp"}
<i class="ti ti-calendar"></i>
{:else if field.field.presentation.t === "Uuid"}
<i class="ti ti-id"></i>
{/if}
</span>
2025-11-12 23:00:30 +00:00
<menu slot="popover" class="basic-dropdown__menu">
<li>
<button
onclick={() => {
field_config_dialog_element?.showModal();
}}
type="button"
>
{field.field.presentation.t} settings
</button>
</li>
<li>
<button
onclick={() => {
remove_field_dialog_element?.showModal();
}}
type="button"
>
Remove field
</button>
</li>
</menu>
2025-10-25 05:32:22 +00:00
</BasicDropdown>
2025-09-08 15:56:57 -07:00
</div>
2025-08-13 18:52:37 -07:00
</div>
2025-11-12 23:00:30 +00:00
<dialog bind:this={remove_field_dialog_element} class="dialog">
<form method="post" action="remove-field">
<div class="padded">
<label style:display="block">
<input type="radio" name="delete_data" value="false" checked />
Hide field without deleting data.
</label>
<label style:display="block">
<input type="radio" name="delete_data" value="true" />
Remove field and underlying data. This cannot be undone.
</label>
</div>
<div class="padded">
<input type="hidden" name="field_id" value={field.field.id} />
<button class="button--primary" type="submit">Remove</button>
<button
class="button--secondary"
onclick={() => {
remove_field_dialog_element?.close();
}}
type="button">Cancel</button
>
</div>
</form>
</dialog>
<dialog bind:this={field_config_dialog_element} class="dialog">
<form method="post" action="update-field">
<div class="padded">
<FieldDetails
bind:name_value
bind:label_value
name_input_disabled
presentation={field.field.presentation}
/>
</div>
<input type="hidden" name="field_id" value={field.field.id} />
<div class="padded">
<button class="button--primary" type="submit">Save</button>
</div>
</form>
</dialog>