1
0
Fork 0
mirror of synced 2024-07-02 13:01:09 +12:00
This commit is contained in:
Martin McKeaveney 2020-06-23 16:20:06 +01:00
parent afcc80ab9d
commit c5bd314931
18 changed files with 397 additions and 335 deletions

View file

@ -12,7 +12,13 @@
let linkedRecords = new Set(linked) let linkedRecords = new Set(linked)
$: linked = [...linkedRecords] $: linked = [...linkedRecords]
$: FIELDS_TO_HIDE = ["modelId", "type", "_id", "_rev", $backendUiStore.selectedModel.name] $: FIELDS_TO_HIDE = [
"modelId",
"type",
"_id",
"_rev",
$backendUiStore.selectedModel.name,
]
async function fetchRecords() { async function fetchRecords() {
const FETCH_RECORDS_URL = `/api/${modelId}/records` const FETCH_RECORDS_URL = `/api/${modelId}/records`
@ -26,7 +32,7 @@
function linkRecord(id) { function linkRecord(id) {
if (linkedRecords.has(id)) { if (linkedRecords.has(id)) {
linkedRecords.delete(id); linkedRecords.delete(id)
} else { } else {
linkedRecords.add(id) linkedRecords.add(id)
} }

View file

@ -4,18 +4,23 @@
import { backendUiStore } from "builderStore" import { backendUiStore } from "builderStore"
import api from "builderStore/api" import api from "builderStore/api"
export let ids = [] export let ids = []
export let header export let header
let records = [] let records = []
let open = false let open = false
$: FIELDS_TO_HIDE = ["modelId", "type", "_id", "_rev", $backendUiStore.selectedModel.name] $: FIELDS_TO_HIDE = [
"modelId",
"type",
"_id",
"_rev",
$backendUiStore.selectedModel.name,
]
async function fetchRecords() { async function fetchRecords() {
const response = await api.post("/api/records/search", { const response = await api.post("/api/records/search", {
keys: ids keys: ids,
}) })
records = await response.json() records = await response.json()
} }

View file

@ -4,7 +4,7 @@
import { Button } from "@budibase/bbui" import { Button } from "@budibase/bbui"
import Select from "components/common/Select.svelte" import Select from "components/common/Select.svelte"
import ActionButton from "components/common/ActionButton.svelte" import ActionButton from "components/common/ActionButton.svelte"
import LinkedRecord from "./LinkedRecord.svelte"; import LinkedRecord from "./LinkedRecord.svelte"
import TablePagination from "./TablePagination.svelte" import TablePagination from "./TablePagination.svelte"
import { DeleteRecordModal, CreateEditRecordModal } from "./modals" import { DeleteRecordModal, CreateEditRecordModal } from "./modals"
import * as api from "./api" import * as api from "./api"
@ -46,9 +46,7 @@
$: { $: {
if ($backendUiStore.selectedView) { if ($backendUiStore.selectedView) {
api api.fetchDataForView($backendUiStore.selectedView).then(records => {
.fetchDataForView($backendUiStore.selectedView)
.then(records => {
data = records || [] data = records || []
headers = Object.keys($backendUiStore.selectedModel.schema).filter( headers = Object.keys($backendUiStore.selectedModel.schema).filter(
key => !INTERNAL_HEADERS.includes(key) key => !INTERNAL_HEADERS.includes(key)
@ -91,10 +89,6 @@
</span> </span>
</Button> </Button>
</div> </div>
<div class="search">
<i class="ri-search-line"></i>
<input placeholder="Search" class="budibase__input" bind:value={search} />
</div>
<table class="uk-table"> <table class="uk-table">
<thead> <thead>
<tr> <tr>
@ -137,9 +131,7 @@
<td> <td>
{#if Array.isArray(row[header])} {#if Array.isArray(row[header])}
<LinkedRecord {header} ids={row[header]} /> <LinkedRecord {header} ids={row[header]} />
{:else} {:else}{row[header] || 0}{/if}
{row[header] || 0}
{/if}
</td> </td>
{/each} {/each}
</tr> </tr>

View file

@ -6,7 +6,6 @@
export let record export let record
export let onClosed export let onClosed
</script> </script>
<section> <section>
@ -26,7 +25,7 @@
alert alert
on:click={async () => { on:click={async () => {
await api.deleteRecord(record) await api.deleteRecord(record)
notifier.danger("Record deleted") notifier.danger('Record deleted')
backendUiStore.actions.records.delete(record) backendUiStore.actions.records.delete(record)
onClosed() onClosed()
}}> }}>

View file

@ -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 = [
@ -11,7 +11,7 @@
{ {
title: "Blocks", title: "Blocks",
key: "BLOCKS", key: "BLOCKS",
} },
] ]
let selectedTab = "FIELDS" let selectedTab = "FIELDS"

View file

@ -14,10 +14,9 @@
backendUiStore.actions.models.save({ backendUiStore.actions.models.save({
model: { model: {
...model, ...model,
...rest ...rest,
}, },
instanceId: $backendUiStore.selectedDatabase._id })
});
} }
</script> </script>
@ -60,7 +59,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(MODELS) as model} {#each Object.values(MODELS) as model}
<Block tertiary title={model.name} icon={model.icon} on:click={() => createModel(model)}/> <Block
tertiary
title={model.name}
icon={model.icon}
on:click={() => createModel(model)} />
{/each} {/each}
</div> </div>
</div> </div>

View file

@ -30,12 +30,11 @@
async function deleteModel() { async function deleteModel() {
const model = $backendUiStore.selectedModel const model = $backendUiStore.selectedModel
const instanceId = $backendUiStore.selectedDatabase._id
const field = $backendUiStore.selectedField const field = $backendUiStore.selectedField
if (field) { if (field) {
delete model.schema[field] delete model.schema[field]
backendUiStore.actions.models.save({ model, instanceId }) backendUiStore.actions.models.save({ model })
notifier.danger(`Field ${field} deleted.`) notifier.danger(`Field ${field} deleted.`)
return return
} }
@ -52,7 +51,6 @@
async function saveModel() { async function saveModel() {
await backendUiStore.actions.models.save({ await backendUiStore.actions.models.save({
instanceId: $backendUiStore.selectedDatabase._id,
model: $backendUiStore.draftModel, model: $backendUiStore.draftModel,
}) })
notifier.success( notifier.success(

View file

@ -1,6 +1,6 @@
<script> <script>
import {buildStyle} from "./helpers.js" import { buildStyle } from "./helpers.js"
import {fade} from "svelte/transition" import { fade } from "svelte/transition"
export let backgroundSize = "10px" export let backgroundSize = "10px"
export let borderRadius = "" export let borderRadius = ""
@ -8,10 +8,13 @@
export let width = "" export let width = ""
export let margin = "" export let margin = ""
$: style = buildStyle({backgroundSize, borderRadius, height, width, margin}) $: style = buildStyle({ backgroundSize, borderRadius, height, width, margin })
</script> </script>
<div in:fade {style}>
<slot />
</div>
<style> <style>
div { div {
background-image: url('data:image/svg+xml;utf8, <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2 2"><path fill="white" d="M1,0H2V1H1V0ZM0,1H1V2H0V1Z"/><path fill="gray" d="M0,0H1V1H0V0ZM1,1H2V2H1V1Z"/></svg>'); background-image: url('data:image/svg+xml;utf8, <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2 2"><path fill="white" d="M1,0H2V1H1V0ZM0,1H1V2H0V1Z"/><path fill="gray" d="M0,0H1V1H0V0ZM1,1H2V2H1V1Z"/></svg>');
@ -19,7 +22,3 @@
width: fit-content; width: fit-content;
} }
</style> </style>
<div in:fade {style}>
<slot />
</div>

View file

@ -1,9 +1,9 @@
<script> <script>
import { onMount, createEventDispatcher } from "svelte"; import { onMount, createEventDispatcher } from "svelte"
import { fade } from 'svelte/transition'; import { fade } from "svelte/transition"
import Swatch from "./Swatch.svelte"; import Swatch from "./Swatch.svelte"
import CheckedBackground from "./CheckedBackground.svelte" import CheckedBackground from "./CheckedBackground.svelte"
import {buildStyle} from "./helpers.js" import { buildStyle } from "./helpers.js"
import { import {
getColorFormat, getColorFormat,
convertToHSVA, convertToHSVA,
@ -14,16 +14,16 @@
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 swatches = [] //TODO: Safe swatches - limit to 12. warn in console export let swatches = [] //TODO: Safe swatches - limit to 12. warn in console
export let disableSwatches = false export let disableSwatches = false
export let format = "hexa"; export let format = "hexa"
export let open = false; export let open = false
export let pickerHeight = 0; export let pickerHeight = 0
export let pickerWidth = 0; export let pickerWidth = 0
let adder = null; let adder = null
let h = null let h = null
let s = null let s = null
@ -33,7 +33,7 @@
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
onMount(() => { onMount(() => {
if(!swatches.length > 0) { if (!swatches.length > 0) {
//Don't use locally stored recent colors if swatches have been passed as props //Don't use locally stored recent colors if swatches have been passed as props
getRecentColors() getRecentColors()
} }
@ -74,24 +74,24 @@
//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)
dispatchValue() dispatchValue()
} }
function setHue({color, isDrag}) { function setHue({ color, isDrag }) {
h = color; h = color
value = convertHsvaToFormat([h, s, v, a], format); value = convertHsvaToFormat([h, s, v, a], format)
if(!isDrag) { if (!isDrag) {
dispatchValue() dispatchValue()
} }
} }
function setAlpha({color, isDrag}) { function setAlpha({ color, isDrag }) {
a = color === "1.00" ? "1" : color; a = color === "1.00" ? "1" : color
value = convertHsvaToFormat([h, s, v, a], format); value = convertHsvaToFormat([h, s, v, a], format)
if(!isDrag) { if (!isDrag) {
dispatchValue() dispatchValue()
} }
} }
@ -101,43 +101,42 @@
} }
function changeFormatAndConvert(f) { function changeFormatAndConvert(f) {
format = f; format = f
value = convertHsvaToFormat([h, s, v, a], format); value = convertHsvaToFormat([h, s, v, a], format)
} }
function handleColorInput(text) { function handleColorInput(text) {
let format = getColorFormat(text) let format = getColorFormat(text)
if(format) { if (format) {
value = text value = text
convertAndSetHSVA() convertAndSetHSVA()
} }
} }
function dispatchInputChange() { function dispatchInputChange() {
if(format) { if (format) {
dispatchValue() dispatchValue()
} }
} }
function addSwatch() { function addSwatch() {
if(format) { if (format) {
dispatch("addswatch", value) dispatch("addswatch", value)
setRecentColor(value) setRecentColor(value)
} }
} }
function removeSwatch(idx) { function removeSwatch(idx) {
let removedSwatch = swatches.splice(idx, 1); let removedSwatch = swatches.splice(idx, 1)
swatches = swatches swatches = swatches
dispatch("removeswatch", removedSwatch) dispatch("removeswatch", removedSwatch)
localStorage.setItem("cp:recent-colors", JSON.stringify(swatches)) localStorage.setItem("cp:recent-colors", JSON.stringify(swatches))
} }
function applySwatch(color) { function applySwatch(color) {
if(value !== color) { if (value !== color) {
format = getColorFormat(color) format = getColorFormat(color)
if(format) { if (format) {
value = color value = color
convertAndSetHSVA() convertAndSetHSVA()
dispatchValue() dispatchValue()
@ -145,8 +144,8 @@
} }
} }
$: border = (v > 90 && s < 5) ? "1px dashed #dedada" : "" $: border = v > 90 && s < 5 ? "1px dashed #dedada" : ""
$: style = buildStyle({background: value, border}) $: style = buildStyle({ background: value, border })
$: shrink = swatches.length > 0 $: shrink = swatches.length > 0
</script> </script>
@ -174,6 +173,73 @@
</div> </div>
</div> </div>
</div>
<div
class="colorpicker-container"
bind:clientHeight={pickerHeight}
bind:clientWidth={pickerWidth}>
<div class="palette-panel">
<Palette on:change={setSaturationAndValue} {h} {s} {v} {a} />
</div>
<div class="control-panel">
<div class="alpha-hue-panel">
<div>
<CheckedBackground borderRadius="50%" backgroundSize="8px">
<div class="selected-color" {style} />
</CheckedBackground>
</div>
<div>
<Slider
type="hue"
value={h}
on:change={hue => setHue(hue.detail)}
on:dragend={dispatchValue} />
<CheckedBackground borderRadius="10px" backgroundSize="7px">
<Slider
type="alpha"
value={a}
on:change={(alpha, isDrag) => setAlpha(alpha.detail, isDrag)}
on:dragend={dispatchValue} />
</CheckedBackground>
</div>
</div>
{#if !disableSwatches}
<div transition:fade class="swatch-panel">
{#if swatches.length > 0}
{#each swatches as color, idx}
<Swatch
{color}
on:click={() => applySwatch(color)}
on:removeswatch={() => removeSwatch(idx)} />
{/each}
{/if}
{#if swatches.length !== 12}
<div
bind:this={adder}
transition:fade
class="adder"
on:click={addSwatch}
class:shrink>
<span>&plus;</span>
</div>
{/if}
</div>
{/if}
<div class="format-input-panel">
<ButtonGroup {format} onclick={changeFormatAndConvert} />
<Input
{value}
on:input={event => handleColorInput(event.target.value)}
on:change={dispatchInputChange} />
</div>
</div>
</div> </div>
<style> <style>
@ -255,54 +321,3 @@
padding-top: 3px; padding-top: 3px;
} }
</style> </style>
<div class="colorpicker-container" bind:clientHeight={pickerHeight} bind:clientWidth={pickerWidth}>
<div class="palette-panel">
<Palette on:change={setSaturationAndValue} {h} {s} {v} {a} />
</div>
<div class="control-panel">
<div class="alpha-hue-panel">
<div>
<CheckedBackground borderRadius="50%" backgroundSize="8px">
<div class="selected-color" {style} />
</CheckedBackground>
</div>
<div>
<Slider type="hue" value={h} on:change={(hue) => setHue(hue.detail)} on:dragend={dispatchValue} />
<CheckedBackground borderRadius="10px" backgroundSize="7px">
<Slider
type="alpha"
value={a}
on:change={(alpha, isDrag) => setAlpha(alpha.detail, isDrag)}
on:dragend={dispatchValue}
/>
</CheckedBackground>
</div>
</div>
{#if !disableSwatches}
<div transition:fade class="swatch-panel">
{#if swatches.length > 0}
{#each swatches as color, idx}
<Swatch {color} on:click={() => applySwatch(color)} on:removeswatch={() => removeSwatch(idx)} />
{/each}
{/if}
{#if swatches.length !== 12}
<div bind:this={adder} transition:fade class="adder" on:click={addSwatch} class:shrink>
<span>&plus;</span>
</div>
{/if}
</div>
{/if}
<div class="format-input-panel">
<ButtonGroup {format} onclick={changeFormatAndConvert} />
<Input {value} on:input={event => handleColorInput(event.target.value)} on:change={dispatchInputChange} />
</div>
</div>
</div>

View file

@ -1,21 +1,21 @@
<script> <script>
import Colorpicker from "./Colorpicker.svelte" import Colorpicker from "./Colorpicker.svelte"
import CheckedBackground from "./CheckedBackground.svelte" import CheckedBackground from "./CheckedBackground.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 swatches = [] export let swatches = []
export let disableSwatches = false export let disableSwatches = false
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
@ -24,36 +24,41 @@
let pickerHeight = 0 let pickerHeight = 0
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`,
left: `${dimensions.left}px`,
})
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
beforeUpdate(() => { beforeUpdate(() => {
format = getColorFormat(value) format = getColorFormat(value)
if(!format) { if (!format) {
errorMsg = `Colorpicker - ${value} is an unknown color format. Please use a hex, rgb or hsl value` errorMsg = `Colorpicker - ${value} is an unknown color format. Please use a hex, rgb or hsl value`
console.error(errorMsg) console.error(errorMsg)
}else{ } else {
errorMsg = null errorMsg = null
} }
}) })
afterUpdate(() => { afterUpdate(() => {
if(colorPreview && colorPreview.offsetParent && !anchorEl) { if (colorPreview && colorPreview.offsetParent && !anchorEl) {
//Anchor relative to closest positioned ancestor element. If none, then anchor to body //Anchor relative to closest positioned ancestor element. If none, then anchor to body
anchorEl = colorPreview.offsetParent anchorEl = colorPreview.offsetParent
let curEl = colorPreview let curEl = colorPreview
let els = [] let els = []
//Travel up dom tree from preview element to find parent elements that scroll //Travel up dom tree from preview element to find parent elements that scroll
while(!anchorEl.isSameNode(curEl)) { while (!anchorEl.isSameNode(curEl)) {
curEl = curEl.parentNode curEl = curEl.parentNode
let elOverflow = window.getComputedStyle(curEl).getPropertyValue("overflow") let elOverflow = window
if(/scroll|auto/.test(elOverflow)) { .getComputedStyle(curEl)
.getPropertyValue("overflow")
if (/scroll|auto/.test(elOverflow)) {
els.push(curEl) els.push(curEl)
} }
} }
@ -61,49 +66,78 @@
} }
}) })
function openColorpicker(event) { function openColorpicker(event) {
if(colorPreview) { if (colorPreview) {
open = true; open = true
} }
} }
$: if(open && colorPreview) { $: if (open && colorPreview) {
const {top: spaceAbove, width, bottom, right, left: spaceLeft} = colorPreview.getBoundingClientRect() const {
const {innerHeight, innerWidth} = window top: spaceAbove,
width,
bottom,
right,
left: spaceLeft,
} = colorPreview.getBoundingClientRect()
const { innerHeight, innerWidth } = window
const {offsetLeft, offsetTop} = colorPreview const { offsetLeft, offsetTop } = colorPreview
//get the scrollTop value for all scrollable parent elements //get the scrollTop value for all scrollable parent elements
let scrollTop = parentNodes.reduce((scrollAcc, el) => scrollAcc += el.scrollTop, 0); let scrollTop = parentNodes.reduce(
(scrollAcc, el) => (scrollAcc += el.scrollTop),
0
)
const spaceBelow = (innerHeight - spaceAbove) - previewHeight const spaceBelow = innerHeight - spaceAbove - previewHeight
const top = spaceAbove > spaceBelow ? (offsetTop - pickerHeight) - scrollTop : (offsetTop + previewHeight) - scrollTop const top =
spaceAbove > spaceBelow
? offsetTop - pickerHeight - scrollTop
: offsetTop + previewHeight - scrollTop
//TOO: Testing and Scroll Awareness for x Scroll //TOO: Testing and Scroll Awareness for x Scroll
const spaceRight = (innerWidth - spaceLeft) + previewWidth const spaceRight = innerWidth - spaceLeft + previewWidth
const left = spaceRight > spaceLeft ? (offsetLeft + previewWidth) : offsetLeft - pickerWidth const left =
spaceRight > spaceLeft
? offsetLeft + previewWidth
: offsetLeft - pickerWidth
dimensions = {top, left} dimensions = { top, left }
} }
function onColorChange(color) { function onColorChange(color) {
value = color.detail; value = color.detail
dispatch("change", color.detail) dispatch("change", color.detail)
} }
</script> </script>
<div class="color-preview-container"> <div class="color-preview-container">
{#if !errorMsg} {#if !errorMsg}
<CheckedBackground borderRadius="3px" backgroundSize="8px"> <CheckedBackground borderRadius="3px" backgroundSize="8px">
<div bind:this={colorPreview} bind:clientHeight={previewHeight} bind:clientWidth={previewWidth} class="color-preview" style={previewStyle} on:click={openColorpicker} /> <div
bind:this={colorPreview}
bind:clientHeight={previewHeight}
bind:clientWidth={previewWidth}
class="color-preview"
style={previewStyle}
on:click={openColorpicker} />
</CheckedBackground> </CheckedBackground>
{#if open} {#if open}
<div transition:fade class="picker-container" style={pickerStyle}> <div transition:fade class="picker-container" style={pickerStyle}>
<Colorpicker on:change={onColorChange} on:addswatch on:removeswatch bind:format bind:value bind:pickerHeight bind:pickerWidth {swatches} {disableSwatches} {open} /> <Colorpicker
on:change={onColorChange}
on:addswatch
on:removeswatch
bind:format
bind:value
bind:pickerHeight
bind:pickerWidth
{swatches}
{disableSwatches}
{open} />
</div> </div>
<div on:click|self={() => open = false} class="overlay"></div> <div on:click|self={() => (open = false)} class="overlay" />
{/if} {/if}
{:else} {:else}
<div class="color-preview preview-error" style={errorPreviewStyle}> <div class="color-preview preview-error" style={errorPreviewStyle}>
@ -112,9 +146,8 @@
{/if} {/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;
@ -140,7 +173,7 @@
height: fit-content; height: fit-content;
} }
.overlay{ .overlay {
position: fixed; position: fixed;
top: 0; top: 0;
bottom: 0; bottom: 0;

View file

@ -5,6 +5,9 @@
<div> <div>
<input on:input type="text" {value} maxlength="25" /> <input on:input type="text" {value} maxlength="25" />
</div> </div>
<div>
<input on:input on:change type="text" {value} maxlength="25" />
</div>
<style> <style>
div { div {
@ -26,7 +29,3 @@
font-weight: 550; font-weight: 550;
} }
</style> </style>
<div>
<input on:input on:change type="text" {value} maxlength="25" />
</div>

View file

@ -1,5 +1,5 @@
<script> <script>
import { onMount, createEventDispatcher } from "svelte"; import { onMount, createEventDispatcher } from "svelte"
import CheckedBackground from "./CheckedBackground.svelte" import CheckedBackground from "./CheckedBackground.svelte"
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
@ -21,7 +21,8 @@
if ( if (
clickX > 0 && clickX > 0 &&
clickY > 0 && clickY > 0 &&
clickX < paletteWidth && clickY < paletteHeight 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
@ -49,6 +50,17 @@
{style}> {style}>
<div class="picker" style={pickerStyle} /> <div class="picker" style={pickerStyle} />
</div> </div>
<CheckedBackground width="100%">
<div
bind:this={palette}
bind:clientHeight={paletteHeight}
bind:clientWidth={paletteWidth}
on:click={handleClick}
class="palette"
{style}>
<div class="picker" style={pickerStyle} />
</div>
</CheckedBackground>
<style> <style>
.palette { .palette {
@ -68,9 +80,3 @@
border-radius: 50%; border-radius: 50%;
} }
</style> </style>
<CheckedBackground width="100%">
<div bind:this={palette} bind:clientHeight={paletteHeight} bind:clientWidth={paletteWidth} on:click={handleClick} class="palette" {style}>
<div class="picker" style={pickerStyle} />
</div>
</CheckedBackground>

View file

@ -11,18 +11,15 @@
let sliderWidth = 0 let sliderWidth = 0
function onSliderChange(mouseX, isDrag = false) { function onSliderChange(mouseX, isDrag = false) {
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"
? 360 * percentageClick
: percentageClick;
dispatch("change", {color: value, isDrag}); dispatch("change", { color: value, isDrag })
} }
} }
@ -45,6 +42,20 @@
class="slider-thumb" class="slider-thumb"
{style} /> {style} />
</div> </div>
<div
bind:this={slider}
bind:clientWidth={sliderWidth}
on:click={event => onSliderChange(event.clientX)}
class="color-format-slider"
class:hue={type === 'hue'}
class:alpha={type === 'alpha'}>
<div
use:dragable
on:drag={e => onSliderChange(e.detail, true)}
on:dragend
class="slider-thumb"
{style} />
</div>
<style> <style>
.color-format-slider { .color-format-slider {
@ -86,18 +97,3 @@
cursor: grab; cursor: grab;
} }
</style> </style>
<div
bind:this={slider}
bind:clientWidth={sliderWidth}
on:click={event => onSliderChange(event.clientX)}
class="color-format-slider"
class:hue={type === 'hue'}
class:alpha={type === 'alpha'}>
<div
use:dragable
on:drag={e => onSliderChange(e.detail, true)}
on:dragend
class="slider-thumb"
{style} />
</div>

View file

@ -1,15 +1,35 @@
<script> <script>
import {createEventDispatcher} from "svelte" import { createEventDispatcher } from "svelte"
import { fade } from 'svelte/transition'; import { fade } from "svelte/transition"
import CheckedBackground from "./CheckedBackground.svelte" import CheckedBackground from "./CheckedBackground.svelte"
export let hovered = false export let hovered = false
export let color = "#fff" export let color = "#fff"
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
</script> </script>
<div class="space">
<CheckedBackground borderRadius="6px">
<div
in:fade
class="swatch"
style={`background: ${color};`}
on:click|self
on:mouseover={() => (hovered = true)}
on:mouseleave={() => (hovered = false)}>
{#if hovered}
<div
in:fade
class="remove-icon"
on:click|self={() => dispatch('removeswatch')}>
<span on:click|self={() => dispatch('removeswatch')}>&times;</span>
</div>
{/if}
</div>
</CheckedBackground>
</div>
<style> <style>
.swatch { .swatch {
position: relative; position: relative;
@ -29,7 +49,7 @@
right: 0; right: 0;
top: -5px; top: -5px;
right: -4px; right: -4px;
width:10px; width: 10px;
height: 10px; height: 10px;
border-radius: 50%; border-radius: 50%;
background-color: #800000; background-color: #800000;
@ -39,15 +59,3 @@
align-items: center; align-items: center;
} }
</style> </style>
<div class="space">
<CheckedBackground borderRadius="6px">
<div in:fade class="swatch" style={`background: ${color};`} on:click|self on:mouseover={() => hovered = true} on:mouseleave={() => hovered = false}>
{#if hovered}
<div in:fade class="remove-icon" on:click|self={()=> dispatch("removeswatch")}>
<span on:click|self={()=> dispatch("removeswatch")}>&times;</span>
</div>
{/if}
</div>
</CheckedBackground>
</div>

View file

@ -162,7 +162,7 @@ export const MODELS = {
Name: BLOCKS.NAME, Name: BLOCKS.NAME,
Cuisine: { Cuisine: {
...FIELDS.PLAIN_TEXT, ...FIELDS.PLAIN_TEXT,
name: "Cuisine" name: "Cuisine",
}, },
}, },
}, },
@ -173,8 +173,8 @@ export const MODELS = {
Name: BLOCKS.NAME, Name: BLOCKS.NAME,
Championships: { Championships: {
...FIELDS.NUMBER, ...FIELDS.NUMBER,
name: "Championships" name: "Championships",
} },
}, },
}, },
} }

View file

@ -1,7 +1,6 @@
const CouchDB = require("../../db") const CouchDB = require("../../db")
const validateJs = require("validate.js") const validateJs = require("validate.js")
const newid = require("../../db/newid") const newid = require("../../db/newid")
const { link } = require("pouchdb-adapter-memory")
exports.save = async function(ctx) { exports.save = async function(ctx) {
const db = new CouchDB(ctx.user.instanceId) const db = new CouchDB(ctx.user.instanceId)
@ -46,7 +45,6 @@ exports.save = async function(ctx) {
// create links in other tables // create links in other tables
for (let key in record) { for (let key in record) {
// link
if (Array.isArray(record[key])) { if (Array.isArray(record[key])) {
const linked = await db.allDocs({ const linked = await db.allDocs({
include_docs: true, include_docs: true,
@ -58,7 +56,9 @@ exports.save = async function(ctx) {
const doc = row.doc const doc = row.doc
return { return {
...doc, ...doc,
[model.name]: doc[model.name] ? [...doc[model.name], record._id] : [record._id] [model.name]: doc[model.name]
? [...doc[model.name], record._id]
: [record._id],
} }
}) })
@ -105,7 +105,7 @@ exports.find = async function(ctx) {
const db = new CouchDB(ctx.user.instanceId) const db = new CouchDB(ctx.user.instanceId)
const record = await db.get(ctx.params.recordId) const record = await db.get(ctx.params.recordId)
if (record.modelId !== ctx.params.modelId) { if (record.modelId !== ctx.params.modelId) {
ctx.throw(400, "Supplied modelId doe not match the record's modelId") ctx.throw(400, "Supplied modelId does not match the records modelId")
return return
} }
ctx.body = record ctx.body = record

View file

@ -23,7 +23,10 @@
const login = async () => { const login = async () => {
loading = true loading = true
const response = await _bb.api.post("/api/authenticate", { username, password }) const response = await _bb.api.post("/api/authenticate", {
username,
password,
})
if (response.status === 200) { if (response.status === 200) {
const json = await response.json() const json = await response.json()
localStorage.setItem("budibase:token", json.token) localStorage.setItem("budibase:token", json.token)