Merge pull request #9951 from Budibase/settings-panel-update

Settings panel layout update
This commit is contained in:
Martin McKeaveney 2023-03-28 18:36:58 +01:00 committed by GitHub
commit bcbed08a40
11 changed files with 282 additions and 319 deletions

View File

@ -7,7 +7,7 @@
export let title export let title
export let fillWidth export let fillWidth
export let left = "314px" export let left = "314px"
export let width = "calc(100% - 576px)" export let width = "calc(100% - 626px)"
let visible = false let visible = false

View File

@ -3,7 +3,6 @@
export let title export let title
export let icon export let icon
export let expandable = false
export let showAddButton = false export let showAddButton = false
export let showBackButton = false export let showBackButton = false
export let showCloseButton = false export let showCloseButton = false
@ -12,8 +11,8 @@
export let onClickCloseButton export let onClickCloseButton
export let borderLeft = false export let borderLeft = false
export let borderRight = false export let borderRight = false
export let wide = false
let wide = false
$: customHeaderContent = $$slots["panel-header-content"] $: customHeaderContent = $$slots["panel-header-content"]
</script> </script>
@ -28,13 +27,6 @@
<div class="title"> <div class="title">
<Heading size="XXS">{title || ""}</Heading> <Heading size="XXS">{title || ""}</Heading>
</div> </div>
{#if expandable}
<Icon
name={wide ? "Minimize" : "Maximize"}
hoverable
on:click={() => (wide = !wide)}
/>
{/if}
{#if showAddButton} {#if showAddButton}
<div class="add-button" on:click={onClickAddButton}> <div class="add-button" on:click={onClickAddButton}>
<Icon name="Add" /> <Icon name="Add" />
@ -74,8 +66,8 @@
border-right: var(--border-light); border-right: var(--border-light);
} }
.panel.wide { .panel.wide {
width: 420px; width: 310px;
flex: 0 0 420px; flex: 0 0 310px;
} }
.header { .header {
flex: 0 0 48px; flex: 0 0 48px;

View File

@ -74,11 +74,13 @@
}) })
</script> </script>
<div class="property-control" class:highlighted={highlighted && nullishValue}> <div
{#if type !== "boolean" && label} class="property-control"
<div class="label"> class:wide={!label}
<Label>{label}</Label> class:highlighted={highlighted && nullishValue}
</div> >
{#if label}
<Label size="M">{label}</Label>
{/if} {/if}
<div id={`${key}-prop-control`} class="control"> <div id={`${key}-prop-control`} class="control">
<svelte:component <svelte:component
@ -90,7 +92,6 @@
onChange={handleChange} onChange={handleChange}
bindings={allBindings} bindings={allBindings}
name={key} name={key}
text={label}
{nested} {nested}
{key} {key}
{type} {type}
@ -105,28 +106,34 @@
<style> <style>
.property-control { .property-control {
position: relative; position: relative;
display: flex; display: grid;
flex-direction: column; grid-template-columns: 90px 1fr;
justify-content: flex-start; align-items: center;
align-items: stretch;
transition: background 130ms ease-out, border-color 130ms ease-out; transition: background 130ms ease-out, border-color 130ms ease-out;
border-left: 4px solid transparent; border-left: 4px solid transparent;
margin: -6px calc(-1 * var(--spacing-xl)); margin: 0 calc(-1 * var(--spacing-xl));
padding: 6px var(--spacing-xl) 6px calc(var(--spacing-xl) - 4px); padding: 0 var(--spacing-xl) 0 calc(var(--spacing-xl) - 4px);
gap: 8px;
}
.property-control :global(.spectrum-FieldLabel) {
white-space: normal;
} }
.property-control.highlighted { .property-control.highlighted {
background: var(--spectrum-global-color-gray-300); background: var(--spectrum-global-color-gray-300);
border-color: var(--spectrum-global-color-blue-400); border-color: var(--spectrum-global-color-blue-400);
} }
.label {
padding-bottom: var(--spectrum-global-dimension-size-65);
}
.control { .control {
position: relative; position: relative;
} }
.property-control.wide .control {
grid-column: 1 / -1;
}
.text { .text {
margin-top: var(--spectrum-global-dimension-size-65);
font-size: var(--spectrum-global-dimension-font-size-75); font-size: var(--spectrum-global-dimension-font-size-75);
color: var(--grey-6); color: var(--grey-6);
grid-column: 2 / 2;
}
.property-control.wide .text {
grid-column: 1 / -1;
} }
</style> </style>

View File

@ -37,7 +37,7 @@
{#if $selectedComponent} {#if $selectedComponent}
{#key $selectedComponent._id} {#key $selectedComponent._id}
<Panel {title} icon={componentDefinition?.icon} borderLeft> <Panel {title} icon={componentDefinition?.icon} borderLeft wide>
<span slot="panel-header-content"> <span slot="panel-header-content">
<div class="settings-tabs"> <div class="settings-tabs">
{#each tabs as tab} {#each tabs as tab}

View File

@ -117,49 +117,51 @@
{#each sections as section, idx (section.name)} {#each sections as section, idx (section.name)}
{#if section.visible} {#if section.visible}
<DetailSummary name={section.name} collapsible={false}> <DetailSummary name={section.name} collapsible={false}>
{#if idx === 0 && !componentInstance._component.endsWith("/layout") && !isScreen} <div class="settings">
<PropertyControl {#if idx === 0 && !componentInstance._component.endsWith("/layout") && !isScreen}
control={Input}
label="Name"
key="_instanceName"
value={componentInstance._instanceName}
onChange={val => updateSetting({ key: "_instanceName" }, val)}
/>
{/if}
{#each section.settings as setting (setting.key)}
{#if setting.visible}
<PropertyControl <PropertyControl
type={setting.type} control={Input}
control={getComponentForSetting(setting)} label="Name"
label={setting.label} key="_instanceName"
key={setting.key} value={componentInstance._instanceName}
value={componentInstance[setting.key]} onChange={val => updateSetting({ key: "_instanceName" }, val)}
defaultValue={setting.defaultValue}
nested={setting.nested}
onChange={val => updateSetting(setting, val)}
highlighted={$store.highlightedSettingKey === setting.key}
info={setting.info}
props={{
// Generic settings
placeholder: setting.placeholder || null,
// Select settings
options: setting.options || [],
// Number fields
min: setting.min ?? null,
max: setting.max ?? null,
}}
{bindings}
{componentBindings}
{componentInstance}
{componentDefinition}
/> />
{/if} {/if}
{/each} {#each section.settings as setting (setting.key)}
{#if idx === 0 && componentDefinition?.component?.endsWith("/fieldgroup")} {#if setting.visible}
<ResetFieldsButton {componentInstance} /> <PropertyControl
{/if} type={setting.type}
control={getComponentForSetting(setting)}
label={setting.label}
key={setting.key}
value={componentInstance[setting.key]}
defaultValue={setting.defaultValue}
nested={setting.nested}
onChange={val => updateSetting(setting, val)}
highlighted={$store.highlightedSettingKey === setting.key}
info={setting.info}
props={{
// Generic settings
placeholder: setting.placeholder || null,
// Select settings
options: setting.options || [],
// Number fields
min: setting.min ?? null,
max: setting.max ?? null,
}}
{bindings}
{componentBindings}
{componentInstance}
{componentDefinition}
/>
{/if}
{/each}
{#if idx === 0 && componentDefinition?.component?.endsWith("/fieldgroup")}
<ResetFieldsButton {componentInstance} />
{/if}
</div>
</DetailSummary> </DetailSummary>
{/if} {/if}
{/each} {/each}
@ -168,3 +170,13 @@
<EjectBlockButton /> <EjectBlockButton />
</DetailSummary> </DetailSummary>
{/if} {/if}
<style>
.settings {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
gap: 8px;
}
</style>

View File

@ -27,7 +27,6 @@
<StyleSection <StyleSection
{style} {style}
name={style.label} name={style.label}
columns={style.columns}
properties={style.settings} properties={style.settings}
{componentInstance} {componentInstance}
{bindings} {bindings}

View File

@ -4,7 +4,6 @@
import { store } from "builderStore" import { store } from "builderStore"
export let name export let name
export let columns
export let properties export let properties
export let componentInstance export let componentInstance
export let bindings = [] export let bindings = []
@ -34,27 +33,27 @@
</script> </script>
<DetailSummary collapsible={false} name={`${name}${changed ? " *" : ""}`}> <DetailSummary collapsible={false} name={`${name}${changed ? " *" : ""}`}>
<div class="group-content" style="grid-template-columns: {columns || '1fr'}"> <div class="styles">
{#each properties as prop (`${componentInstance._id}-${prop.key}-${prop.label}`)} {#each properties as prop (`${componentInstance._id}-${prop.key}-${prop.label}`)}
<div style="grid-column: {prop.column || 'auto'}"> <PropertyControl
<PropertyControl label={`${prop.label}${hasPropChanged(style, prop) ? " *" : ""}`}
label={`${prop.label}${hasPropChanged(style, prop) ? " *" : ""}`} control={prop.control}
control={prop.control} key={prop.key}
key={prop.key} value={style[prop.key]}
value={style[prop.key]} onChange={val => updateStyle(prop.key, val)}
onChange={val => updateStyle(prop.key, val)} props={getControlProps(prop)}
props={getControlProps(prop)} {bindings}
{bindings} />
/>
</div>
{/each} {/each}
</div> </div>
</DetailSummary> </DetailSummary>
<style> <style>
.group-content { .styles {
display: grid; display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch; align-items: stretch;
gap: var(--spacing-l); gap: 8px;
} }
</style> </style>

View File

@ -3,7 +3,6 @@ import ColorPicker from "components/design/settings/controls/ColorPicker.svelte"
export const margin = { export const margin = {
label: "Margin", label: "Margin",
columns: "1fr 1fr",
settings: [ settings: [
{ {
label: "Top", label: "Top",
@ -90,7 +89,6 @@ export const margin = {
export const padding = { export const padding = {
label: "Padding", label: "Padding",
columns: "1fr 1fr",
settings: [ settings: [
{ {
label: "Top", label: "Top",
@ -177,7 +175,6 @@ export const padding = {
export const size = { export const size = {
label: "Size", label: "Size",
columns: "1fr 1fr",
settings: [ settings: [
{ {
label: "Width", label: "Width",
@ -196,7 +193,6 @@ export const size = {
export const background = { export const background = {
label: "Background", label: "Background",
columns: "auto 1fr",
settings: [ settings: [
{ {
label: "Color", label: "Color",
@ -285,7 +281,6 @@ export const background = {
export const border = { export const border = {
label: "Border", label: "Border",
columns: "1fr 1fr",
settings: [ settings: [
{ {
label: "Color", label: "Color",

View File

@ -1,22 +1,13 @@
<script> <script>
import Panel from "components/design/Panel.svelte" import Panel from "components/design/Panel.svelte"
import { goto } from "@roxi/routify" import { goto } from "@roxi/routify"
import { import { Layout, Search, Icon, Body, notifications } from "@budibase/bbui"
Layout,
ActionGroup,
ActionButton,
Search,
Icon,
Body,
notifications,
} from "@budibase/bbui"
import structure from "./componentStructure.json" import structure from "./componentStructure.json"
import { store, selectedComponent, selectedScreen } from "builderStore" import { store, selectedComponent, selectedScreen } from "builderStore"
import { onMount } from "svelte" import { onMount } from "svelte"
import { fly } from "svelte/transition" import { fly } from "svelte/transition"
import { findComponentPath } from "builderStore/componentUtils" import { findComponentPath } from "builderStore/componentUtils"
let section = "components"
let searchString let searchString
let searchRef let searchRef
let selectedIndex let selectedIndex
@ -37,7 +28,6 @@
allowedComponents, allowedComponents,
searchString searchString
) )
$: blocks = enrichedStructure.find(x => x.name === "Blocks").children
$: orderMap = createComponentOrderMap(componentList) $: orderMap = createComponentOrderMap(componentList)
const getAllowedComponents = (allComponents, screen, component) => { const getAllowedComponents = (allComponents, screen, component) => {
@ -127,6 +117,11 @@
} }
}) })
// Swap blocks and plugins
let tmp = enrichedStructure[1]
enrichedStructure[1] = enrichedStructure[0]
enrichedStructure[0] = tmp
return enrichedStructure return enrichedStructure
} }
@ -137,11 +132,6 @@
return [] return []
} }
// Remove blocks if there is no search string
if (!search) {
structure = structure.filter(category => category.name !== "Blocks")
}
// Return only items which match the search string // Return only items which match the search string
let filteredStructure = [] let filteredStructure = []
structure.forEach(category => { structure.forEach(category => {
@ -225,6 +215,7 @@
showCloseButton showCloseButton
onClickCloseButton={() => $goto("../")} onClickCloseButton={() => $goto("../")}
borderLeft borderLeft
wide
> >
<Layout paddingX="L" paddingY="XL" gap="S"> <Layout paddingX="L" paddingY="XL" gap="S">
<Search <Search
@ -233,64 +224,31 @@
on:change={e => (searchString = e.detail)} on:change={e => (searchString = e.detail)}
bind:inputRef={searchRef} bind:inputRef={searchRef}
/> />
{#if !searchString} {#if filteredStructure.length}
<ActionGroup compact justified> {#each filteredStructure as category}
<ActionButton <Layout noPadding gap="XS">
fullWidth <div class="category-label">{category.name}</div>
selected={section === "components"} {#each category.children as component}
on:click={() => (section = "components")}>Components</ActionButton <div
> draggable="true"
<ActionButton on:dragstart={() => onDragStart(component.component)}
fullWidth on:dragend={onDragEnd}
selected={section === "blocks"} class="component"
on:click={() => (section = "blocks")}>Blocks</ActionButton class:selected={selectedIndex === orderMap[component.component]}
> on:click={() => addComponent(component.component)}
</ActionGroup> on:mouseover={() => (selectedIndex = null)}
{/if} on:focus
{#if searchString || section === "components"} >
{#if filteredStructure.length} <Icon name={component.icon} />
{#each filteredStructure as category} <Body size="XS">{component.name}</Body>
<Layout noPadding gap="XS"> </div>
<div class="category-label">{category.name}</div> {/each}
{#each category.children as component} </Layout>
<div {/each}
draggable="true"
on:dragstart={() => onDragStart(component.component)}
on:dragend={onDragEnd}
class="component"
class:selected={selectedIndex ===
orderMap[component.component]}
on:click={() => addComponent(component.component)}
on:mouseover={() => (selectedIndex = null)}
on:focus
>
<Icon name={component.icon} />
<Body size="XS">{component.name}</Body>
</div>
{/each}
</Layout>
{/each}
{:else}
<Body size="S">
There aren't any components matching the current filter
</Body>
{/if}
{:else} {:else}
<Body size="S">Blocks are collections of pre-built components</Body> <Body size="S">
<Layout noPadding gap="XS"> There aren't any components matching the current filter
{#each blocks as block} </Body>
<div
draggable="true"
class="component"
on:click={() => addComponent(block.component)}
on:dragstart={() => onDragStart(block.component)}
on:dragend={onDragEnd}
>
<Icon name={block.icon} />
<Body size="XS">{block.name}</Body>
</div>
{/each}
</Layout>
{/if} {/if}
</Layout> </Layout>
</Panel> </Panel>

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@
let width = window.innerWidth let width = window.innerWidth
let height = window.innerHeight let height = window.innerHeight
const tabletBreakpoint = 768 const tabletBreakpoint = 720
const desktopBreakpoint = 1280 const desktopBreakpoint = 1280
const resizeObserver = new ResizeObserver(entries => { const resizeObserver = new ResizeObserver(entries => {
if (entries?.[0]) { if (entries?.[0]) {