Multiple improvement to option configuration

This commit is contained in:
Andrew Kingston 2024-05-21 13:59:33 +01:00
parent f30142831e
commit d9a00cc6d4
1 changed files with 107 additions and 136 deletions

View File

@ -2,7 +2,7 @@
import { flip } from "svelte/animate" import { flip } from "svelte/animate"
import { dndzone } from "svelte-dnd-action" import { dndzone } from "svelte-dnd-action"
import { Icon, Popover } from "@budibase/bbui" import { Icon, Popover } from "@budibase/bbui"
import { onMount } from "svelte" import { onMount, tick } from "svelte"
import { Constants } from "@budibase/frontend-core" import { Constants } from "@budibase/frontend-core"
export let constraints export let constraints
@ -22,13 +22,16 @@
anchors.pop(undefined) anchors.pop(undefined)
} }
const addNewInput = () => { const addNewInput = async () => {
const newOption = `Option ${constraints.inclusion.length + 1}` const newName = `Option ${constraints.inclusion.length + 1}`
options = [...options, { name: newOption, id: Math.random() }] const id = Math.random()
constraints.inclusion = [...constraints.inclusion, newOption] options = [...options, { name: newName, id }]
optionColors[newOption] = Constants.OptionColours[(options.length - 1) % 9] constraints.inclusion = [...constraints.inclusion, newName]
optionColors[newName] = Constants.OptionColours[(options.length - 1) % 9]
colorPopovers.push(undefined) colorPopovers.push(undefined)
anchors.push(undefined) anchors.push(undefined)
await tick()
document.getElementById(`option-${id}`)?.focus()
} }
const handleDndConsider = e => { const handleDndConsider = e => {
@ -75,154 +78,101 @@
<!-- svelte-ignore a11y-no-static-element-interactions --> <!-- svelte-ignore a11y-no-static-element-interactions -->
<!-- svelte-ignore a11y-click-events-have-key-events --> <!-- svelte-ignore a11y-click-events-have-key-events -->
<div> <div
<div class="options"
class="actions" use:dndzone={{
use:dndzone={{ items: options,
items: options, flipDurationMs,
flipDurationMs, dropTargetStyle: { outline: "none" },
dropTargetStyle: { outline: "none" }, }}
}} on:consider={handleDndConsider}
on:consider={handleDndConsider} on:finalize={handleDndFinalize}
on:finalize={handleDndFinalize} >
> {#each options as option, idx (`${option.id}-${idx}`)}
{#each options as option, idx (`${option.id}-${idx}`)} <div class="option" animate:flip={{ duration: flipDurationMs }}>
<div class="drag-handle">
<Icon name="DragHandle" size="L" />
</div>
<div <div
class="no-border action-container" bind:this={anchors[idx]}
animate:flip={{ duration: flipDurationMs }} class="color-picker"
on:click={e => openColorPickerPopover(idx, e.target)}
> >
<div class="child drag-handle-spacing">
<Icon name="DragHandle" size="L" />
</div>
<div <div
bind:this={anchors[idx]} class="circle"
class="child color-picker" style="--color:{optionColors?.[option.name] ||
on:click={e => openColorPickerPopover(idx, e.target)} 'hsla(0, 1%, 50%, 0.3)'}"
> >
<div <Popover
class="circle" bind:this={colorPopovers[idx]}
style="--color:{optionColors?.[option.name] || anchor={anchors[idx]}
'hsla(0, 1%, 50%, 0.3)'}" align="left"
offset={0}
animate={false}
> >
<Popover <div class="colors" data-ignore-click-outside="true">
bind:this={colorPopovers[idx]} {#each Constants.OptionColours as color}
anchor={anchors[idx]} <div
align="left" on:click={() => handleColorChange(option.name, color, idx)}
offset={0} style="--color:{color};"
animate={false} class="circle circle-hover"
> />
<div class="colors" data-ignore-click-outside="true"> {/each}
{#each Constants.OptionColours as color} </div>
<div </Popover>
on:click={() => handleColorChange(option.name, color, idx)}
style="--color:{color};"
class="circle circle-hover"
/>
{/each}
</div>
</Popover>
</div>
</div>
<div class="child">
<input
class="input-field"
type="text"
on:change={e => handleNameChange(option.name, idx, e.target.value)}
value={option.name}
placeholder="Option name"
/>
</div>
<div class="child">
<Icon name="Close" hoverable size="S" on:click={removeInput(idx)} />
</div> </div>
</div> </div>
{/each} <input
</div> class="option-name"
type="text"
on:change={e => handleNameChange(option.name, idx, e.target.value)}
value={option.name}
placeholder="Option name"
id="option-{option.id}"
/>
<Icon name="Close" hoverable size="S" on:click={removeInput(idx)} />
</div>
{/each}
<div on:click={addNewInput} class="add-option"> <div on:click={addNewInput} class="add-option">
<Icon hoverable name="Add" /> <Icon name="Add" />
<div>Add option</div> <div>Add option</div>
</div> </div>
</div> </div>
<style> <style>
.action-container { /* Container */
background-color: var(--spectrum-alias-background-color-primary); .options {
border-radius: 0px; overflow: hidden;
border-radius: 4px;
border: 1px solid var(--spectrum-global-color-gray-300); border: 1px solid var(--spectrum-global-color-gray-300);
background-color: var(--spectrum-global-color-gray-50);
}
.options > * {
height: 32px;
}
/* Options row */
.option {
transition: background-color 130ms ease-in-out, color 130ms ease-in-out, transition: background-color 130ms ease-in-out, color 130ms ease-in-out,
border-color 130ms ease-in-out; border-color 130ms ease-in-out;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
} border-bottom: 1px solid var(--spectrum-global-color-gray-300);
.no-border {
border-bottom: none;
}
.action-container:last-child {
border-bottom: 1px solid var(--spectrum-global-color-gray-300) !important;
}
.child {
height: 30px;
}
.child:hover,
.child:focus {
background: var(--spectrum-global-color-gray-200);
}
.add-option {
display: flex;
flex-direction: row;
align-items: center;
padding: var(--spacing-m);
gap: var(--spacing-m); gap: var(--spacing-m);
cursor: pointer; padding: 0 var(--spacing-m) 0 var(--spacing-s);
}
.option:hover,
.option:focus {
background: var(--spectrum-global-color-gray-100);
} }
.input-field { /* Option row components */
border: none; .color-picker {
outline: none; align-self: stretch;
background-color: transparent; display: grid;
width: 100%; place-items: center;
color: var(--text);
} }
.child input[type="text"] {
padding-left: 10px;
}
.input-field:hover,
.input-field:focus {
background: var(--spectrum-global-color-gray-200);
}
.action-container > :nth-child(1) {
flex-grow: 1;
justify-content: center;
display: flex;
}
.action-container > :nth-child(2) {
flex-grow: 1;
display: flex;
justify-content: center;
align-items: center;
}
.action-container > :nth-child(3) {
flex-grow: 4;
display: flex;
}
.action-container > :nth-child(4) {
flex-grow: 1;
justify-content: center;
display: flex;
}
.color-picker:hover {
cursor: pointer;
}
.circle { .circle {
height: 20px; height: 20px;
width: 20px; width: 20px;
@ -230,18 +180,39 @@
border-radius: 50%; border-radius: 50%;
display: inline-block; display: inline-block;
box-sizing: border-box; box-sizing: border-box;
border: 1px solid transparent;
transition: border 130ms ease-out;
} }
.circle:hover {
.circle-hover:hover { border: 1px solid var(--spectrum-global-color-blue-600);
border: 1px solid var(--spectrum-global-color-blue-400);
cursor: pointer; cursor: pointer;
} }
.colors { .colors {
display: grid; display: grid;
grid-template-columns: 1fr 1fr 1fr; grid-template-columns: 1fr 1fr 1fr 1fr;
gap: var(--spacing-xl); gap: var(--spacing-xl);
justify-items: center; justify-items: center;
margin: var(--spacing-m); margin: var(--spacing-m);
} }
.option-name {
border: none;
outline: none;
background-color: transparent;
width: 100%;
color: var(--text);
}
/* Add option */
.add-option {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
padding: var(--spacing-m);
gap: var(--spacing-m);
}
.add-option:hover {
cursor: pointer !important;
background: var(--spectrum-global-color-gray-200);
}
</style> </style>