Browse Source

lint ✨

gh-pages
Martin McKeaveney 6 years ago
parent
commit
099e394270
  1. 45
      packages/builder/src/builderStore/store/backend.js
  2. 3
      packages/builder/src/components/common/Block.svelte
  3. 6
      packages/builder/src/components/common/LinkedRecordSelector.svelte
  4. 6
      packages/builder/src/components/database/ModelDataTable/modals/CreateEditRecord.svelte
  5. 4
      packages/builder/src/components/nav/HierarchyRow.svelte
  6. 2
      packages/builder/src/components/nav/ModelNavigator/BlockNavigator.svelte
  7. 24
      packages/builder/src/components/nav/ModelNavigator/EmptyModel.svelte
  8. 16
      packages/builder/src/components/nav/ModelNavigator/ModelNavigator.svelte
  9. 70
      packages/builder/src/components/nav/ModelSetupNav/ModelFieldEditor.svelte
  10. 4
      packages/builder/src/components/nav/ModelSetupNav/ModelSetupNav.svelte
  11. 2
      packages/builder/src/components/nav/ModelSetupNav/index.js
  12. 26
      packages/builder/src/components/userInterface/Colorpicker/ButtonGroup.svelte
  13. 122
      packages/builder/src/components/userInterface/Colorpicker/Colorpicker.svelte
  14. 289
      packages/builder/src/components/userInterface/Colorpicker/Colorpreview.svelte
  15. 8
      packages/builder/src/components/userInterface/Colorpicker/FlatButton.svelte
  16. 10
      packages/builder/src/components/userInterface/Colorpicker/Input.svelte
  17. 55
      packages/builder/src/components/userInterface/Colorpicker/Palette.svelte
  18. 61
      packages/builder/src/components/userInterface/Colorpicker/Slider.svelte
  19. 38
      packages/builder/src/components/userInterface/DesignView.svelte
  20. 2
      packages/builder/src/components/userInterface/PropertyControl.svelte
  21. 112
      packages/builder/src/constants/backend/index.js
  22. 2
      packages/builder/src/pages/[application]/backend/database/[selectedDatabase]/_layout.svelte
  23. 4
      packages/builder/src/pages/[application]/backend/database/[selectedDatabase]/index.svelte

45
packages/builder/src/builderStore/store/backend.js

@ -1,5 +1,5 @@
import { writable } from "svelte/store" import { writable } from "svelte/store"
import { cloneDeep } from "lodash/fp"; import { cloneDeep } from "lodash/fp"
import api from "../api" import api from "../api"
export const getBackendUiStore = () => { export const getBackendUiStore = () => {
@ -12,8 +12,8 @@ export const getBackendUiStore = () => {
draftModel: {}, draftModel: {},
tabs: { tabs: {
SETUP_PANEL: "SETUP", SETUP_PANEL: "SETUP",
NAVIGATION_PANEL: "NAVIGATE" NAVIGATION_PANEL: "NAVIGATE",
} },
} }
const store = writable(INITIAL_BACKEND_UI_STATE) const store = writable(INITIAL_BACKEND_UI_STATE)
@ -28,7 +28,7 @@ export const getBackendUiStore = () => {
store.update(state => { store.update(state => {
state.selectedDatabase = db state.selectedDatabase = db
if (models && models.length > 0) { if (models && models.length > 0) {
store.actions.models.select(models[0]); store.actions.models.select(models[0])
} }
state.models = models state.models = models
state.views = views state.views = views
@ -49,24 +49,25 @@ export const getBackendUiStore = () => {
}), }),
}, },
models: { models: {
select: model => store.update(state => { select: model =>
state.selectedModel = model; store.update(state => {
state.draftModel = cloneDeep(model); state.selectedModel = model
state.selectedField = "" state.draftModel = cloneDeep(model)
state.selectedView = `all_${model._id}` state.selectedField = ""
state.tabs.SETUP_PANEL = "SETUP" state.selectedView = `all_${model._id}`
return state; state.tabs.SETUP_PANEL = "SETUP"
}), return state
}),
save: async ({ instanceId, model }) => { save: async ({ instanceId, model }) => {
const updatedModel = cloneDeep(model); const updatedModel = cloneDeep(model)
// TODO: refactor // TODO: refactor
for (let key in updatedModel.schema) { for (let key in updatedModel.schema) {
const field = updatedModel.schema[key] const field = updatedModel.schema[key]
if (field.name && field.name !== key) { if (field.name && field.name !== key) {
updatedModel.schema[field.name] = field updatedModel.schema[field.name] = field
delete updatedModel.schema[key]; delete updatedModel.schema[key]
} }
} }
const SAVE_MODEL_URL = `/api/${instanceId}/models` const SAVE_MODEL_URL = `/api/${instanceId}/models`
@ -78,8 +79,10 @@ export const getBackendUiStore = () => {
if (!model._id) { if (!model._id) {
state.models = [...state.models, savedModel] state.models = [...state.models, savedModel]
} else { } else {
const existingIdx = state.models.findIndex(({ _id }) => _id === model._id); const existingIdx = state.models.findIndex(
state.models.splice(existingIdx, 1, savedModel); ({ _id }) => _id === model._id
)
state.models.splice(existingIdx, 1, savedModel)
state.models = state.models state.models = state.models
} }
@ -95,7 +98,7 @@ export const getBackendUiStore = () => {
state.draftModel.schema = { state.draftModel.schema = {
...state.draftModel.schema, ...state.draftModel.schema,
[field.name]: field [field.name]: field,
} }
state.selectedField = field.name state.selectedField = field.name
@ -103,7 +106,7 @@ export const getBackendUiStore = () => {
state.tabs.NAVIGATION_PANEL = "NAVIGATE" state.tabs.NAVIGATION_PANEL = "NAVIGATE"
return state return state
}); })
}, },
}, },
views: { views: {

3
packages/builder/src/components/common/Block.svelte

@ -30,7 +30,7 @@
i { i {
font-size: 30px; font-size: 30px;
} }
span { span {
font-size: 14px; font-size: 14px;
text-align: center; text-align: center;
@ -53,5 +53,4 @@
.tertiary { .tertiary {
background: var(--white); background: var(--white);
} }
</style> </style>

6
packages/builder/src/components/common/LinkedRecordSelector.svelte

@ -1,5 +1,5 @@
<script> <script>
import { onMount } from "svelte"; import { onMount } from "svelte"
import { backendUiStore } from "builderStore" import { backendUiStore } from "builderStore"
import api from "builderStore/api" import api from "builderStore/api"
@ -19,7 +19,7 @@
}) })
function linkRecord(record) { function linkRecord(record) {
linkedRecords.push(record); linkedRecords.push(record)
} }
</script> </script>
@ -65,4 +65,4 @@
font-size: 14px; font-size: 14px;
word-break: break-word; word-break: break-word;
} }
</style> </style>

6
packages/builder/src/components/database/ModelDataTable/modals/CreateEditRecord.svelte

@ -1,7 +1,7 @@
<script> <script>
import { onMount } from "svelte" import { onMount } from "svelte"
import { store, backendUiStore } from "builderStore" import { store, backendUiStore } from "builderStore"
import { notifier } from "@beyonk/svelte-notifications"; import { notifier } from "@beyonk/svelte-notifications"
import { compose, map, get, flatten } from "lodash/fp" import { compose, map, get, flatten } from "lodash/fp"
import ActionButton from "components/common/ActionButton.svelte" import ActionButton from "components/common/ActionButton.svelte"
import LinkedRecordSelector from "components/common/LinkedRecordSelector.svelte" import LinkedRecordSelector from "components/common/LinkedRecordSelector.svelte"
@ -64,7 +64,7 @@
backendUiStore.update(state => { backendUiStore.update(state => {
state.selectedView = state.selectedView state.selectedView = state.selectedView
onClosed() onClosed()
notifier.success("Record created successfully."); notifier.success("Record created successfully.")
return state return state
}) })
} }
@ -76,7 +76,7 @@
<form on:submit|preventDefault class="uk-form-stacked"> <form on:submit|preventDefault class="uk-form-stacked">
{#each modelSchema as [key, meta]} {#each modelSchema as [key, meta]}
<div class="uk-margin"> <div class="uk-margin">
{#if meta.type === "link"} {#if meta.type === 'link'}
<LinkedRecordSelector modelId={meta.modelId} /> <LinkedRecordSelector modelId={meta.modelId} />
{:else} {:else}
<RecordFieldControl <RecordFieldControl

4
packages/builder/src/components/nav/HierarchyRow.svelte

@ -3,9 +3,7 @@
import { store, backendUiStore } from "builderStore" import { store, backendUiStore } from "builderStore"
import { cloneDeep } from "lodash/fp" import { cloneDeep } from "lodash/fp"
import getIcon from "../common/icon" import getIcon from "../common/icon"
import { import { CreateEditViewModal } from "components/database/ModelDataTable/modals"
CreateEditViewModal,
} from "components/database/ModelDataTable/modals"
import api from "builderStore/api" import api from "builderStore/api"
const { open, close } = getContext("simple-modal") const { open, close } = getContext("simple-modal")

2
packages/builder/src/components/nav/ModelNavigator/BlockNavigator.svelte

@ -1,6 +1,6 @@
<script> <script>
import * as blockDefinitions from "constants/backend" import * as blockDefinitions from "constants/backend"
import { backendUiStore } from "builderStore"; import { backendUiStore } from "builderStore"
import Block from "components/common/Block.svelte" import Block from "components/common/Block.svelte"
const HEADINGS = [ const HEADINGS = [

24
packages/builder/src/components/nav/ModelNavigator/EmptyModel.svelte

@ -1,11 +1,11 @@
<script> <script>
import { backendUiStore } from "builderStore"; import { backendUiStore } from "builderStore"
import { fade } from 'svelte/transition'; import { fade } from "svelte/transition"
import { FIELDS, BLOCKS, MODELS } from "constants/backend"; import { FIELDS, BLOCKS, MODELS } from "constants/backend"
import Block from "components/common/Block.svelte"; import Block from "components/common/Block.svelte"
function addNewField(field) { function addNewField(field) {
backendUiStore.actions.models.addField(field); backendUiStore.actions.models.addField(field)
} }
</script> </script>
@ -20,7 +20,11 @@
<p>Blocks are pre-made fields and help you build your model quicker.</p> <p>Blocks are pre-made fields and help you build your model quicker.</p>
<div class="blocks"> <div class="blocks">
{#each Object.values(FIELDS) as field} {#each Object.values(FIELDS) as field}
<Block primary title={field.name} icon={field.icon} on:click={() => addNewField(field)} /> <Block
primary
title={field.name}
icon={field.icon}
on:click={() => addNewField(field)} />
{/each} {/each}
</div> </div>
</div> </div>
@ -30,7 +34,11 @@
<p>Blocks are pre-made fields and help you build your model quicker.</p> <p>Blocks are pre-made fields and help you build your model quicker.</p>
<div class="blocks"> <div class="blocks">
{#each Object.values(BLOCKS) as field} {#each Object.values(BLOCKS) as field}
<Block secondary title={field.name} icon={field.icon} on:click={() => addNewField(field)} /> <Block
secondary
title={field.name}
icon={field.icon}
on:click={() => addNewField(field)} />
{/each} {/each}
</div> </div>
</div> </div>
@ -78,4 +86,4 @@
grid-auto-columns: 110px; grid-auto-columns: 110px;
grid-gap: 20px; grid-gap: 20px;
} }
</style> </style>

16
packages/builder/src/components/nav/ModelNavigator/ModelNavigator.svelte

@ -1,6 +1,6 @@
<script> <script>
import { getContext } from "svelte" import { getContext } from "svelte"
import { slide } from 'svelte/transition'; import { slide } from "svelte/transition"
import { Switcher } from "@budibase/bbui" import { Switcher } from "@budibase/bbui"
import { goto } from "@sveltech/routify" import { goto } from "@sveltech/routify"
import { store, backendUiStore } from "builderStore" import { store, backendUiStore } from "builderStore"
@ -21,7 +21,7 @@
}, },
] ]
$: selectedTab = $backendUiStore.tabs.NAVIGATION_PANEL $: selectedTab = $backendUiStore.tabs.NAVIGATION_PANEL
function selectModel(model, fieldName) { function selectModel(model, fieldName) {
backendUiStore.actions.models.select(model) backendUiStore.actions.models.select(model)
@ -30,7 +30,7 @@
backendUiStore.update(state => { backendUiStore.update(state => {
state.selectedField = fieldName state.selectedField = fieldName
return state return state
}); })
} }
} }
@ -47,10 +47,14 @@
{#if $backendUiStore.selectedDatabase && $backendUiStore.selectedDatabase._id} {#if $backendUiStore.selectedDatabase && $backendUiStore.selectedDatabase._id}
<div class="hierarchy"> <div class="hierarchy">
<div class="components-list-container"> <div class="components-list-container">
<Switcher headings={HEADINGS} bind:value={$backendUiStore.tabs.NAVIGATION_PANEL}> <Switcher
headings={HEADINGS}
bind:value={$backendUiStore.tabs.NAVIGATION_PANEL}>
{#if selectedTab === 'NAVIGATE'} {#if selectedTab === 'NAVIGATE'}
<Button secondary wide on:click={setupForNewModel}>Create New Model</Button> <Button secondary wide on:click={setupForNewModel}>
<div class="hierarchy-items-container"> Create New Model
</Button>
<div class="hierarchy-items-container">
{#each $backendUiStore.models as model} {#each $backendUiStore.models as model}
<ListItem <ListItem
selected={!$backendUiStore.selectedField && model._id === $backendUiStore.selectedModel._id} selected={!$backendUiStore.selectedField && model._id === $backendUiStore.selectedModel._id}

70
packages/builder/src/components/nav/ModelSetupNav/ModelFieldEditor.svelte

@ -38,44 +38,42 @@
</div> </div>
</div> </div>
<div class="info"> <div class="info">
<div class="field">
<label>Required</label>
<input type="checkbox" />
</div>
{#if field.type === 'string'}
<NumberBox
label="Max Length"
bind:value={field.constraints.length.maximum} />
<ValuesList label="Categories" bind:values={field.constraints.inclusion} />
{:else if field.type === 'datetime'}
<DatePicker
label="Min Value"
bind:value={field.constraints.datetime.earliest} />
<DatePicker
label="Max Value"
bind:value={field.constraints.datetime.latest} />
{:else if field.type === 'number'}
<NumberBox
label="Min Value"
bind:value={field.constraints.numericality.greaterThanOrEqualTo} />
<NumberBox
label="Max Value"
bind:value={field.constraints.numericality.lessThanOrEqualTo} />
{:else if field.type === 'link'}
<div class="field"> <div class="field">
<label>Required</label> <label>Link</label>
<input type="checkbox" /> <select class="budibase__input" bind:value={field.modelId}>
<option value={''} />
{#each $backendUiStore.models as model}
<option value={model._id}>{model.name}</option>
{/each}
</select>
</div> </div>
{/if}
{#if field.type === 'string'}
<NumberBox
label="Max Length"
bind:value={field.constraints.length.maximum} />
<ValuesList
label="Categories"
bind:values={field.constraints.inclusion} />
{:else if field.type === 'datetime'}
<DatePicker
label="Min Value"
bind:value={field.constraints.datetime.earliest} />
<DatePicker
label="Max Value"
bind:value={field.constraints.datetime.latest} />
{:else if field.type === 'number'}
<NumberBox
label="Min Value"
bind:value={field.constraints.numericality.greaterThanOrEqualTo} />
<NumberBox
label="Max Value"
bind:value={field.constraints.numericality.lessThanOrEqualTo} />
{:else if field.type === 'link'}
<div class="field">
<label>Link</label>
<select class="budibase__input" bind:value={field.modelId}>
<option value={''} />
{#each $backendUiStore.models as model}
<option value={model._id}>{model.name}</option>
{/each}
</select>
</div>
{/if}
</div> </div>
<style> <style>

4
packages/builder/src/components/nav/ModelSetupNav/ModelSetupNav.svelte

@ -25,8 +25,8 @@
$: edited = $: edited =
$backendUiStore.selectedField || $backendUiStore.selectedField ||
$backendUiStore.draftModel && ($backendUiStore.draftModel &&
$backendUiStore.draftModel.name !== $backendUiStore.selectedModel.name $backendUiStore.draftModel.name !== $backendUiStore.selectedModel.name)
async function deleteModel() { async function deleteModel() {
const model = $backendUiStore.selectedModel const model = $backendUiStore.selectedModel

2
packages/builder/src/components/nav/ModelSetupNav/index.js

@ -1 +1 @@
export { default as ModelSetupNav } from "./ModelSetupNav.svelte"; export { default as ModelSetupNav } from "./ModelSetupNav.svelte"

26
packages/builder/src/components/userInterface/Colorpicker/ButtonGroup.svelte

@ -1,12 +1,21 @@
<script> <script>
import FlatButton from "./FlatButton.svelte"; import FlatButton from "./FlatButton.svelte"
export let format = "hex"; export let format = "hex"
export let onclick = format => {}; export let onclick = format => {}
let colorFormats = ["hex", "rgb", "hsl"]; let colorFormats = ["hex", "rgb", "hsl"]
</script> </script>
<div class="flatbutton-group">
{#each colorFormats as text}
<FlatButton
selected={format === text}
{text}
on:click={() => onclick(text)} />
{/each}
</div>
<style> <style>
.flatbutton-group { .flatbutton-group {
font-weight: 500; font-weight: 500;
@ -16,12 +25,3 @@
justify-content: center; justify-content: center;
} }
</style> </style>
<div class="flatbutton-group">
{#each colorFormats as text}
<FlatButton
selected={format === text}
{text}
on:click={() => onclick(text)} />
{/each}
</div>

122
packages/builder/src/components/userInterface/Colorpicker/Colorpicker.svelte

@ -1,80 +1,105 @@
<script> <script>
import { onMount, createEventDispatcher } from "svelte"; import { onMount, createEventDispatcher } from "svelte"
import { import {
getColorFormat, getColorFormat,
convertToHSVA, convertToHSVA,
convertHsvaToFormat convertHsvaToFormat,
} from "./utils.js"; } from "./utils.js"
import Slider from "./Slider.svelte"; import Slider from "./Slider.svelte"
import Palette from "./Palette.svelte"; import Palette from "./Palette.svelte"
import ButtonGroup from "./ButtonGroup.svelte"; import ButtonGroup from "./ButtonGroup.svelte"
import Input from "./Input.svelte"; import Input from "./Input.svelte"
export let value = "#3ec1d3ff"; export let value = "#3ec1d3ff"
export let format = "hexa"; export let format = "hexa"
let h = null; let h = null
let s = null; let s = null
let v = null; let v = null
let a = null; let a = null
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher()
onMount(() => { onMount(() => {
if (format) { if (format) {
convertAndSetHSVA() convertAndSetHSVA()
} }
}); })
function convertAndSetHSVA() { function convertAndSetHSVA() {
let hsva = convertToHSVA(value, format); let hsva = convertToHSVA(value, format)
setHSVA(hsva); setHSVA(hsva)
} }
function setHSVA([hue, sat, val, alpha]) { function setHSVA([hue, sat, val, alpha]) {
h = hue; h = hue
s = sat; s = sat
v = val; v = val
a = alpha; a = alpha
} }
//fired by choosing a color from the palette //fired by choosing a color from the palette
function setSaturationAndValue({ detail }) { function setSaturationAndValue({ detail }) {
s = detail.s; s = detail.s
v = detail.v; v = detail.v
value = convertHsvaToFormat([h, s, v, a], format); value = convertHsvaToFormat([h, s, v, a], format)
dispatch("change", value) dispatch("change", value)
} }
function setHue(hue) { function setHue(hue) {
h = hue; h = hue
value = convertHsvaToFormat([h, s, v, a], format); value = convertHsvaToFormat([h, s, v, a], format)
} }
function setAlpha(alpha) { function setAlpha(alpha) {
a = alpha === "1.00" ? "1" :alpha; a = alpha === "1.00" ? "1" : alpha
value = convertHsvaToFormat([h, s, v, a], format); value = convertHsvaToFormat([h, s, v, a], format)
} }
function changeFormatAndConvert(f) { function changeFormatAndConvert(f) {
format = f; format = f
console.log(f) console.log(f)
value = convertHsvaToFormat([h, s, v, a], format); value = convertHsvaToFormat([h, s, v, a], format)
} }
function handleColorInput(text) { function handleColorInput(text) {
let f = getColorFormat(text) let f = getColorFormat(text)
if(f) { if (f) {
format = f; format = f
value = text value = text
convertAndSetHSVA() convertAndSetHSVA()
dispatch("change", value) dispatch("change", value)
} }
} }
</script> </script>
<div class="colorpicker-container">
<Palette on:change={setSaturationAndValue} {h} {s} {v} {a} />
<div class="control-panel">
<div class="alpha-hue-panel">
<div>
<div class="selected-color" style={`background: ${value}`} />
</div>
<div>
<Slider type="hue" value={h} on:change={hue => setHue(hue.detail)} />
<Slider
type="alpha"
value={a}
on:change={alpha => setAlpha(alpha.detail)} />
</div>
</div>
<div class="format-input-panel">
<ButtonGroup {format} onclick={changeFormatAndConvert} />
<Input {value} on:input={event => handleColorInput(event.target.value)} />
</div>
</div>
</div>
<style> <style>
.colorpicker-container { .colorpicker-container {
display: flex; display: flex;
@ -85,7 +110,8 @@
width: 250px; width: 250px;
background: #ffffff; background: #ffffff;
border-radius: 2px; border-radius: 2px;
box-shadow: 0 0.15em 1.5em 0 rgba(0,0,0,.1), 0 0 1em 0 rgba(0,0,0,.03); box-shadow: 0 0.15em 1.5em 0 rgba(0, 0, 0, 0.1),
0 0 1em 0 rgba(0, 0, 0, 0.03);
} }
.control-panel { .control-panel {
@ -93,7 +119,7 @@
flex-direction: column; flex-direction: column;
padding: 8px; padding: 8px;
background: white; background: white;
border: 1px solid #d2d2d2 border: 1px solid #d2d2d2;
} }
.alpha-hue-panel { .alpha-hue-panel {
@ -117,29 +143,3 @@
justify-content: center; justify-content: center;
} }
</style> </style>
<div class="colorpicker-container">
<Palette on:change={setSaturationAndValue} {h} {s} {v} {a} />
<div class="control-panel">
<div class="alpha-hue-panel">
<div>
<div class="selected-color" style={`background: ${value}`} />
</div>
<div>
<Slider type="hue" value={h} on:change={hue => setHue(hue.detail)} />
<Slider
type="alpha"
value={a}
on:change={alpha => setAlpha(alpha.detail)} />
</div>
</div>
<div class="format-input-panel">
<ButtonGroup {format} onclick={changeFormatAndConvert} />
<Input {value} on:input={event => handleColorInput(event.target.value)} />
</div>
</div>
</div>

289
packages/builder/src/components/userInterface/Colorpicker/Colorpreview.svelte

@ -1,143 +1,170 @@
<script> <script>
import Colorpicker from "./Colorpicker.svelte" import Colorpicker from "./Colorpicker.svelte"
import {createEventDispatcher, afterUpdate, beforeUpdate} from "svelte" import { createEventDispatcher, afterUpdate, beforeUpdate } from "svelte"
import {buildStyle} from "./helpers.js" import { buildStyle } from "./helpers.js"
import { fade } from 'svelte/transition'; import { fade } from "svelte/transition"
import {getColorFormat} from "./utils.js" import { getColorFormat } from "./utils.js"
export let value = "#3ec1d3ff" export let value = "#3ec1d3ff"
export let open = false; export let open = false
export let width = "25px" export let width = "25px"
export let height = "25px" export let height = "25px"
let format = "hexa"; let format = "hexa"
let dimensions = {top: 0, left: 0} let dimensions = { top: 0, left: 0 }
let colorPreview = null let colorPreview = null
let previewHeight = null let previewHeight = null
let previewWidth = null let previewWidth = null
let pickerWidth = 250 let pickerWidth = 250
let pickerHeight = 300 let pickerHeight = 300
let anchorEl = null let anchorEl = null
let parentNodes = []; let parentNodes = []
let errorMsg = null let errorMsg = null
$: previewStyle = buildStyle({width, height, background: value}) $: previewStyle = buildStyle({ width, height, background: value })
$: errorPreviewStyle = buildStyle({width, height}) $: errorPreviewStyle = buildStyle({ width, height })
$: pickerStyle = buildStyle({top: `${dimensions.top}px`, left: `${dimensions.left}px`}) $: pickerStyle = buildStyle({
top: `${dimensions.top}px`,
const dispatch = createEventDispatcher() left: `${dimensions.left}px`,
})
beforeUpdate(() => {
format = getColorFormat(value) const dispatch = createEventDispatcher()
if(!format) {
errorMsg = `Colorpicker - ${value} is an unknown color format. Please use a hex, rgb or hsl value` beforeUpdate(() => {
console.error(errorMsg) format = getColorFormat(value)
}else{ if (!format) {
errorMsg = null errorMsg = `Colorpicker - ${value} is an unknown color format. Please use a hex, rgb or hsl value`
} console.error(errorMsg)
}) } else {
errorMsg = null
afterUpdate(() => { }
if(colorPreview && colorPreview.offsetParent && !anchorEl) { })
//Anchor relative to closest positioned ancestor element. If none, then anchor to body
anchorEl = colorPreview.offsetParent afterUpdate(() => {
let curEl = colorPreview if (colorPreview && colorPreview.offsetParent && !anchorEl) {
let els = [] //Anchor relative to closest positioned ancestor element. If none, then anchor to body
//Travel up dom tree from preview element to find parent elements that scroll anchorEl = colorPreview.offsetParent
while(!anchorEl.isSameNode(curEl)) { let curEl = colorPreview
curEl = curEl.parentNode let els = []
let elOverflow = window.getComputedStyle(curEl).getPropertyValue("overflow") //Travel up dom tree from preview element to find parent elements that scroll
if(/scroll|auto/.test(elOverflow)) { while (!anchorEl.isSameNode(curEl)) {
els.push(curEl) curEl = curEl.parentNode
} let elOverflow = window
} .getComputedStyle(curEl)
parentNodes = els .getPropertyValue("overflow")
} if (/scroll|auto/.test(elOverflow)) {
}) els.push(curEl)
function openColorpicker(event) {
if(colorPreview) {
const {top: spaceAbove, width, bottom, right, left: spaceLeft} = colorPreview.getBoundingClientRect()
const {innerHeight, innerWidth} = window
const {offsetLeft, offsetTop} = colorPreview
//get the scrollTop value for all scrollable parent elements
let scrollTop = parentNodes.reduce((scrollAcc, el) => scrollAcc += el.scrollTop, 0);
const spaceBelow = (innerHeight - spaceAbove) - previewHeight
const top = spaceAbove > spaceBelow ? (offsetTop - pickerHeight) - scrollTop : (offsetTop + previewHeight) - scrollTop
//TOO: Testing and Scroll Awareness for x Scroll
const spaceRight = (innerWidth - spaceLeft) + previewWidth
const left = spaceRight > spaceLeft ? (offsetLeft + previewWidth) + pickerWidth : offsetLeft - pickerWidth
dimensions = {top, left}
open = true;
} }
}
parentNodes = els
} }
})
function onColorChange(color) {
value = color.detail; function openColorpicker(event) {
dispatch("change", color.detail) if (colorPreview) {
const {
top: spaceAbove,
width,
bottom,
right,
left: spaceLeft,
} = colorPreview.getBoundingClientRect()
const { innerHeight, innerWidth } = window
const { offsetLeft, offsetTop } = colorPreview
//get the scrollTop value for all scrollable parent elements
let scrollTop = parentNodes.reduce(
(scrollAcc, el) => (scrollAcc += el.scrollTop),
0
)
const spaceBelow = innerHeight - spaceAbove - previewHeight
const top =
spaceAbove > spaceBelow
? offsetTop - pickerHeight - scrollTop
: offsetTop + previewHeight - scrollTop
//TOO: Testing and Scroll Awareness for x Scroll
const spaceRight = innerWidth - spaceLeft + previewWidth
const left =
spaceRight > spaceLeft
? offsetLeft + previewWidth + pickerWidth
: offsetLeft - pickerWidth
dimensions = { top, left }
open = true
} }
}
function onColorChange(color) {
value = color.detail
dispatch("change", color.detail)
}
</script> </script>
<div class="color-preview-container"> <div class="color-preview-container">
{#if !errorMsg} {#if !errorMsg}
<div bind:this={colorPreview} bind:clientHeight={previewHeight} bind:clientWidth={previewWidth} class="color-preview" style={previewStyle} on:click={openColorpicker}></div> <div
{#if open} bind:this={colorPreview}
<div class="picker-container" bind:clientHeight={pickerHeight} bind:clientWidth={pickerWidth} style={pickerStyle}> bind:clientHeight={previewHeight}
<Colorpicker on:change={onColorChange} {format} {value} /> bind:clientWidth={previewWidth}
</div> class="color-preview"
<div on:click|self={() => open = false} class="overlay"></div> style={previewStyle}
{/if} on:click={openColorpicker} />
{:else} {#if open}
<div class="color-preview preview-error" style={errorPreviewStyle}> <div
<span>&times;</span> class="picker-container"
</div> bind:clientHeight={pickerHeight}
bind:clientWidth={pickerWidth}
style={pickerStyle}>
<Colorpicker on:change={onColorChange} {format} {value} />
</div>
<div on:click|self={() => (open = false)} class="overlay" />
{/if} {/if}
{:else}
<div class="color-preview preview-error" style={errorPreviewStyle}>
<span>&times;</span>
</div>
{/if}
</div> </div>
<style> <style>
.color-preview-container{ .color-preview-container {
display: flex; display: flex;
flex-flow: row nowrap; flex-flow: row nowrap;
height: fit-content; height: fit-content;
} }
.color-preview { .color-preview {
flex: 1; flex: 1;
border-radius: 3px; border-radius: 3px;
border: 1px solid #dedada; border: 1px solid #dedada;
} }
.preview-error { .preview-error {
background: #cccccc; background: #cccccc;
color: #808080; color: #808080;
text-align: center; text-align: center;
font-size: 18px; font-size: 18px;
cursor: not-allowed; cursor: not-allowed;
} }
.picker-container { .picker-container {
position: absolute; position: absolute;
z-index: 3; z-index: 3;
width: fit-content; width: fit-content;
height: fit-content; height: fit-content;
} }
.overlay{ .overlay {
position: fixed; position: fixed;
top: 0; top: 0;
bottom: 0; bottom: 0;
left: 0; left: 0;
right: 0; right: 0;
z-index: 2; z-index: 2;
} }
</style> </style>

8
packages/builder/src/components/userInterface/Colorpicker/FlatButton.svelte

@ -1,8 +1,10 @@
<script> <script>
export let text = ""; export let text = ""
export let selected = false; export let selected = false
</script> </script>
<div class="flatbutton" class:selected on:click>{text}</div>
<style> <style>
.flatbutton { .flatbutton {
padding: 3px 15px; padding: 3px 15px;
@ -22,5 +24,3 @@
border: none; border: none;
} }
</style> </style>
<div class="flatbutton" class:selected on:click>{text}</div>

10
packages/builder/src/components/userInterface/Colorpicker/Input.svelte

@ -1,7 +1,11 @@
<script> <script>
export let value = ""; export let value = ""
</script> </script>
<div>
<input on:input type="text" {value} maxlength="25" />
</div>
<style> <style>
div { div {
display: flex; display: flex;
@ -22,7 +26,3 @@
border: 1px solid #dadada; border: 1px solid #dadada;
} }
</style> </style>
<div>
<input on:input type="text" {value} maxlength="25" />
</div>

55
packages/builder/src/components/userInterface/Colorpicker/Palette.svelte

@ -1,41 +1,54 @@
<script> <script>
import { onMount, createEventDispatcher } from "svelte"; import { onMount, createEventDispatcher } from "svelte"
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
export let h = 0; export let h = 0
export let s = 0; export let s = 0
export let v = 0; export let v = 0
export let a = 1; export let a = 1
let palette; let palette
let paletteHeight, paletteWidth = 0;
let paletteHeight,
paletteWidth = 0
function handleClick(event) { function handleClick(event) {
const { left, top } = palette.getBoundingClientRect(); const { left, top } = palette.getBoundingClientRect()
let clickX = (event.clientX - left) let clickX = event.clientX - left
let clickY = (event.clientY - top) let clickY = event.clientY - top
if((clickX > 0 && clickY > 0) && (clickX < paletteWidth && clickY < paletteHeight)) { if (
clickX > 0 &&
clickY > 0 &&
clickX < paletteWidth && clickY < paletteHeight
) {
let s = (clickX / paletteWidth) * 100 let s = (clickX / paletteWidth) * 100
let v = 100 - ((clickY / paletteHeight) * 100) let v = 100 - (clickY / paletteHeight) * 100
dispatch("change", {s, v}) dispatch("change", { s, v })
} }
} }
$: pickerX = (s * paletteWidth) / 100; $: pickerX = (s * paletteWidth) / 100
$: pickerY = paletteHeight * ((100 - v) / 100) $: pickerY = paletteHeight * ((100 - v) / 100)
$: paletteGradient = `linear-gradient(to top, rgba(0, 0, 0, 1), transparent), $: paletteGradient = `linear-gradient(to top, rgba(0, 0, 0, 1), transparent),
linear-gradient(to left, hsla(${h}, 100%, 50%, ${a}), rgba(255, 255, 255, ${a})) linear-gradient(to left, hsla(${h}, 100%, 50%, ${a}), rgba(255, 255, 255, ${a}))
`; `
$: style = `background: ${paletteGradient};`; $: style = `background: ${paletteGradient};`
$: pickerStyle = `transform: translate(${pickerX - 8}px, ${pickerY - 8}px);` $: pickerStyle = `transform: translate(${pickerX - 8}px, ${pickerY - 8}px);`
</script> </script>
<div
bind:this={palette}
bind:clientHeight={paletteHeight}
bind:clientWidth={paletteWidth}
on:click={handleClick}
class="palette"
{style}>
<div class="picker" style={pickerStyle} />
</div>
<style> <style>
.palette { .palette {
position: relative; position: relative;
@ -54,7 +67,3 @@
border-radius: 50%; border-radius: 50%;
} }
</style> </style>
<div bind:this={palette} bind:clientHeight={paletteHeight} bind:clientWidth={paletteWidth} on:click={handleClick} class="palette" {style}>
<div class="picker" style={pickerStyle} />
</div>

61
packages/builder/src/components/userInterface/Colorpicker/Slider.svelte

@ -1,36 +1,47 @@
<script> <script>
import { onMount, createEventDispatcher } from "svelte"; import { onMount, createEventDispatcher } from "svelte"
import dragable from "./drag.js"; import dragable from "./drag.js"
export let value = 1; export let value = 1
export let type = "hue"; export let type = "hue"
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher()
let slider; let slider
let sliderWidth = 0; let sliderWidth = 0
function handleClick(mouseX) { function handleClick(mouseX) {
const { left, width } = slider.getBoundingClientRect(); const { left, width } = slider.getBoundingClientRect()
let clickPosition = mouseX - left; let clickPosition = mouseX - left
let percentageClick = (clickPosition / sliderWidth).toFixed(2) let percentageClick = (clickPosition / sliderWidth).toFixed(2)
if (percentageClick >= 0 && percentageClick <= 1) { if (percentageClick >= 0 && percentageClick <= 1) {
let value = let value = type === "hue" ? 360 * percentageClick : percentageClick
type === "hue" dispatch("change", value)
? 360 * percentageClick
: percentageClick;
dispatch("change", value);
} }
} }
$: thumbPosition = $: thumbPosition =
type === "hue" ? sliderWidth * (value / 360) : sliderWidth * value; type === "hue" ? sliderWidth * (value / 360) : sliderWidth * value
$: style = `transform: translateX(${thumbPosition - 6}px);`; $: style = `transform: translateX(${thumbPosition - 6}px);`
</script> </script>
<div
bind:this={slider}
bind:clientWidth={sliderWidth}
on:click={event => handleClick(event.clientX)}
class="color-format-slider"
class:hue={type === 'hue'}
class:alpha={type === 'alpha'}>
<div
use:dragable
on:drag={e => handleClick(e.detail)}
class="slider-thumb"
{style} />
</div>
<style> <style>
.color-format-slider { .color-format-slider {
position: relative; position: relative;
@ -68,20 +79,6 @@
border: 1px solid #777676; border: 1px solid #777676;
border-radius: 50%; border-radius: 50%;
background-color: #ffffff; background-color: #ffffff;
cursor:grab; cursor: grab;
} }
</style> </style>
<div
bind:this={slider}
bind:clientWidth={sliderWidth}
on:click={event => handleClick(event.clientX)}
class="color-format-slider"
class:hue={type === 'hue'}
class:alpha={type === 'alpha'}>
<div
use:dragable
on:drag={e => handleClick(e.detail)}
class="slider-thumb"
{style} />
</div>

38
packages/builder/src/components/userInterface/DesignView.svelte

@ -31,26 +31,26 @@
<FlatButtonGroup value={selectedCategory} {buttonProps} {onChange} /> <FlatButtonGroup value={selectedCategory} {buttonProps} {onChange} />
</div> </div>
<div class="positioned-wrapper"> <div class="positioned-wrapper">
<div class="design-view-property-groups"> <div class="design-view-property-groups">
{#if propertyGroupNames.length > 0} {#if propertyGroupNames.length > 0}
{#each propertyGroupNames as groupName} {#each propertyGroupNames as groupName}
<PropertyGroup <PropertyGroup
name={groupName} name={groupName}
properties={getProperties(groupName)} properties={getProperties(groupName)}
styleCategory={selectedCategory} styleCategory={selectedCategory}
{onStyleChanged} {onStyleChanged}
{componentDefinition} {componentDefinition}
{componentInstance} /> {componentInstance} />
{/each} {/each}
{:else} {:else}
<div class="no-design"> <div class="no-design">
<span>This component does not have any design properties</span> <span>This component does not have any design properties</span>
</div> </div>
{/if} {/if}
</div>
</div> </div>
</div> </div>
</div>
<style> <style>
.design-view-container { .design-view-container {
@ -64,7 +64,7 @@
flex: 0 0 50px; flex: 0 0 50px;
} }
.positioned-wrapper{ .positioned-wrapper {
position: relative; position: relative;
display: flex; display: flex;
min-height: 0; min-height: 0;

2
packages/builder/src/components/userInterface/PropertyControl.svelte

@ -12,7 +12,7 @@
if (v.target) { if (v.target) {
let val = props.valueKey ? v.target[props.valueKey] : v.target.value let val = props.valueKey ? v.target[props.valueKey] : v.target.value
onChange(key, val) onChange(key, val)
}else if(v.detail) { } else if (v.detail) {
onChange(key, v.detail) onChange(key, v.detail)
} else { } else {
onChange(key, v) onChange(key, v)

112
packages/builder/src/constants/backend/index.js

@ -1,5 +1,3 @@
const FIELD_TYPES = ["string", "number", "boolean"]
export const FIELDS = { export const FIELDS = {
PLAIN_TEXT: { PLAIN_TEXT: {
name: "Plain Text", name: "Plain Text",
@ -30,52 +28,52 @@ export const FIELDS = {
presence: false, presence: false,
}, },
}, },
// OPTIONS: { OPTIONS: {
// name: "Options", name: "Options",
// icon: "ri-list-check-2", icon: "ri-list-check-2",
// type: "options", type: "options",
// constraints: { constraints: {
// type: "string", type: "string",
// presence: false, presence: false,
// }, },
// }, },
// DATETIME: { DATETIME: {
// name: "Date/Time", name: "Date/Time",
// icon: "ri-calendar-event-fill", icon: "ri-calendar-event-fill",
// type: "datetime", type: "datetime",
// constraints: { constraints: {
// type: "date", type: "date",
// datetime: {}, datetime: {},
// presence: false, presence: false,
// }, },
// }, },
// IMAGE: { IMAGE: {
// name: "File", name: "File",
// icon: "ri-image-line", icon: "ri-image-line",
// type: "file", type: "file",
// constraints: { constraints: {
// type: "string", type: "string",
// presence: false, presence: false,
// }, },
// }, },
// FILE: { FILE: {
// name: "Image", name: "Image",
// icon: "ri-file-line", icon: "ri-file-line",
// type: "file", type: "file",
// constraints: { constraints: {
// type: "string", type: "string",
// presence: false, presence: false,
// }, },
// }, },
// DATA_LINK: { DATA_LINK: {
// name: "Data Links", name: "Data Links",
// icon: "ri-link", icon: "ri-link",
// type: "link", type: "link",
// modelId: null, modelId: null,
// constraints: { constraints: {
// type: "array", type: "array",
// } },
// }, },
} }
export const BLOCKS = { export const BLOCKS = {
@ -115,11 +113,7 @@ export const BLOCKS = {
constraints: { constraints: {
type: "string", type: "string",
presence: false, presence: false,
inclusion: [ inclusion: ["low", "medium", "high"],
"low",
"medium",
"high"
]
}, },
}, },
END_DATE: { END_DATE: {
@ -157,7 +151,7 @@ export const BLOCKS = {
modelId: null, modelId: null,
constraints: { constraints: {
type: "array", type: "array",
} },
}, },
} }
@ -168,15 +162,15 @@ export const MODELS = {
name: "Contacts", name: "Contacts",
schema: { schema: {
Name: BLOCKS.NAME, Name: BLOCKS.NAME,
"Phone Number": BLOCKS.PHONE_NUMBER "Phone Number": BLOCKS.PHONE_NUMBER,
} },
}, },
RECIPES: { RECIPES: {
icon: "ri-link", icon: "ri-link",
name: "Recipes", name: "Recipes",
schema: { schema: {
Name: BLOCKS.NAME, Name: BLOCKS.NAME,
"Phone Number": BLOCKS.PHONE_NUMBER "Phone Number": BLOCKS.PHONE_NUMBER,
} },
} },
} }

2
packages/builder/src/pages/[application]/backend/database/[selectedDatabase]/_layout.svelte

@ -1 +1 @@
<slot /> <slot />

4
packages/builder/src/pages/[application]/backend/database/[selectedDatabase]/index.svelte

@ -1,6 +1,6 @@
<script> <script>
import { getContext } from "svelte" import { getContext } from "svelte"
import { Button } from "@budibase/bbui"; import { Button } from "@budibase/bbui"
import EmptyModel from "components/nav/ModelNavigator/EmptyModel.svelte" import EmptyModel from "components/nav/ModelNavigator/EmptyModel.svelte"
import ModelDataTable from "components/database/ModelDataTable" import ModelDataTable from "components/database/ModelDataTable"
import { store, backendUiStore } from "builderStore" import { store, backendUiStore } from "builderStore"
@ -10,7 +10,7 @@
const { open, close } = getContext("simple-modal") const { open, close } = getContext("simple-modal")
$: selectedModel = $backendUiStore.selectedModel $: selectedModel = $backendUiStore.selectedModel
const createNewRecord = () => { const createNewRecord = () => {
open( open(

Loading…
Cancel
Save