mirror of https://github.com/Budibase/budibase.git
199 changed files with 1793 additions and 8693 deletions
@ -1,59 +0,0 @@ |
|||||
<script> |
|
||||
export let title |
|
||||
export let icon |
|
||||
|
|
||||
export let primary |
|
||||
export let secondary |
|
||||
export let tertiary |
|
||||
</script> |
|
||||
|
|
||||
<div on:click class:primary class:secondary class:tertiary> |
|
||||
<i class={icon} /> |
|
||||
<span>{title}</span> |
|
||||
</div> |
|
||||
|
|
||||
<style> |
|
||||
div { |
|
||||
height: 80px; |
|
||||
border-radius: 5px; |
|
||||
color: var(--ink); |
|
||||
font-weight: 400; |
|
||||
padding: 15px; |
|
||||
display: flex; |
|
||||
justify-content: center; |
|
||||
align-items: center; |
|
||||
flex-direction: column; |
|
||||
transition: 0.3s transform; |
|
||||
background: var(--grey-1); |
|
||||
} |
|
||||
|
|
||||
i { |
|
||||
font-size: 24px; |
|
||||
color: var(--grey-7); |
|
||||
} |
|
||||
|
|
||||
span { |
|
||||
font-size: 14px; |
|
||||
text-align: center; |
|
||||
margin-top: 8px; |
|
||||
line-height: 1.25; |
|
||||
} |
|
||||
|
|
||||
div:hover { |
|
||||
cursor: pointer; |
|
||||
background: var(--grey-2); |
|
||||
} |
|
||||
|
|
||||
.primary { |
|
||||
background: var(--ink); |
|
||||
color: var(--white); |
|
||||
} |
|
||||
|
|
||||
.secondary { |
|
||||
background: var(--blue-light); |
|
||||
} |
|
||||
|
|
||||
.tertiary { |
|
||||
background: var(--white); |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,20 +0,0 @@ |
|||||
<script> |
|
||||
import { JavaScriptIcon } from "../common/Icons" |
|
||||
// todo: use https://ace.c9.io |
|
||||
export let text = "" |
|
||||
</script> |
|
||||
|
|
||||
<textarea class="uk-textarea" bind:value={text} /> |
|
||||
|
|
||||
<style> |
|
||||
textarea { |
|
||||
padding: 10px; |
|
||||
margin-top: 5px; |
|
||||
margin-bottom: 10px; |
|
||||
background: var(--grey-7); |
|
||||
color: var(--white); |
|
||||
font-family: "Courier New", Courier, monospace; |
|
||||
height: 200px; |
|
||||
border-radius: 5px; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,13 +0,0 @@ |
|||||
<script> |
|
||||
export let name = "" |
|
||||
</script> |
|
||||
|
|
||||
<div> |
|
||||
<h4>Coming Sometime: {name}</h4> |
|
||||
</div> |
|
||||
|
|
||||
<style> |
|
||||
h4 { |
|
||||
margin-top: 20px; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,45 +0,0 @@ |
|||||
<script> |
|
||||
import { createEventDispatcher } from "svelte" |
|
||||
import Select from "../common/Select.svelte" |
|
||||
|
|
||||
export let selected |
|
||||
export let label |
|
||||
export let options |
|
||||
export let valueMember |
|
||||
export let textMember |
|
||||
export let multiple = false |
|
||||
export let width = "medium" |
|
||||
export let size = "small" |
|
||||
|
|
||||
const dispatch = createEventDispatcher() |
|
||||
</script> |
|
||||
|
|
||||
<div class="uk-margin"> |
|
||||
<label class="uk-form-label">{label}</label> |
|
||||
<div class="uk-form-controls"> |
|
||||
{#if multiple} |
|
||||
<Select |
|
||||
class="uk-select uk-form-width-{width} uk-form-{size}" |
|
||||
multiple |
|
||||
bind:value={selected} |
|
||||
on:change> |
|
||||
{#each options as option} |
|
||||
<option value={!valueMember ? option : valueMember(option)}> |
|
||||
{!textMember ? option : textMember(option)} |
|
||||
</option> |
|
||||
{/each} |
|
||||
</Select> |
|
||||
{:else} |
|
||||
<Select |
|
||||
class="uk-select uk-form-width-{width} uk-form-{size}" |
|
||||
bind:value={selected} |
|
||||
on:change> |
|
||||
{#each options as option} |
|
||||
<option value={!valueMember ? option : valueMember(option)}> |
|
||||
{!textMember ? option : textMember(option)} |
|
||||
</option> |
|
||||
{/each} |
|
||||
</Select> |
|
||||
{/if} |
|
||||
</div> |
|
||||
</div> |
|
||||
@ -1,62 +0,0 @@ |
|||||
<script> |
|
||||
import { onMount } from "svelte" |
|
||||
import { buildStyle } from "../../helpers.js" |
|
||||
export let value = "" |
|
||||
export let name = "" |
|
||||
export let textAlign = "left" |
|
||||
export let width = "160px" |
|
||||
export let placeholder = "" |
|
||||
export let suffix = "" |
|
||||
export let onChange = val => {} |
|
||||
|
|
||||
let centerPlaceholder = textAlign === "center" |
|
||||
|
|
||||
let style = buildStyle({ width, textAlign }) |
|
||||
|
|
||||
function handleChange(val) { |
|
||||
value = val |
|
||||
let _value = value !== "auto" ? value + suffix : value |
|
||||
onChange(_value) |
|
||||
} |
|
||||
|
|
||||
$: displayValue = |
|
||||
suffix && value && value.endsWith(suffix) |
|
||||
? value.replace(new RegExp(`${suffix}$`), "") |
|
||||
: value || "" |
|
||||
</script> |
|
||||
|
|
||||
<input |
|
||||
{name} |
|
||||
class:centerPlaceholder |
|
||||
type="text" |
|
||||
value={displayValue} |
|
||||
{placeholder} |
|
||||
{style} |
|
||||
on:change={e => handleChange(e.target.value)} /> |
|
||||
|
|
||||
<style> |
|
||||
input { |
|
||||
/* width: 32px; */ |
|
||||
height: 36px; |
|
||||
font-size: 14px; |
|
||||
font-weight: 400; |
|
||||
margin: 0px 0px 0px 2px; |
|
||||
color: var(--ink); |
|
||||
padding: 0px 8px; |
|
||||
font-family: inter; |
|
||||
width: 164px; |
|
||||
box-sizing: border-box; |
|
||||
background-color: var(--grey-2); |
|
||||
border-radius: 4px; |
|
||||
border: 1px solid var(--grey-2); |
|
||||
outline: none; |
|
||||
} |
|
||||
|
|
||||
input::placeholder { |
|
||||
text-align: left; |
|
||||
} |
|
||||
|
|
||||
.centerPlaceholder::placeholder { |
|
||||
text-align: center; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,50 +0,0 @@ |
|||||
<script> |
|
||||
import { onMount } from "svelte" |
|
||||
import Input from "../Input.svelte" |
|
||||
|
|
||||
export let meta = [] |
|
||||
export let label = "" |
|
||||
export let value = ["0", "0", "0", "0"] |
|
||||
export let suffix = "" |
|
||||
|
|
||||
export let onChange = () => {} |
|
||||
|
|
||||
function handleChange(val, idx) { |
|
||||
value.splice(idx, 1, val !== "auto" && suffix ? val + suffix : val) |
|
||||
|
|
||||
value = value |
|
||||
let _value = value.map(v => |
|
||||
suffix && !v.endsWith(suffix) && v !== "auto" ? v + suffix : v |
|
||||
) |
|
||||
onChange(_value) |
|
||||
} |
|
||||
|
|
||||
$: displayValues = |
|
||||
value && suffix |
|
||||
? value.map(v => v.replace(new RegExp(`${suffix}$`), "")) |
|
||||
: value || [] |
|
||||
</script> |
|
||||
|
|
||||
<div class="input-container"> |
|
||||
<div class="label">{label}</div> |
|
||||
<div class="inputs-group"> |
|
||||
{#each meta as m, i} |
|
||||
<Input |
|
||||
width="37px" |
|
||||
textAlign="center" |
|
||||
placeholder={m.placeholder || ''} |
|
||||
value={!displayValues || displayValues[i] === '0' ? '' : displayValues[i]} |
|
||||
onChange={value => handleChange(value || 0, i)} /> |
|
||||
{/each} |
|
||||
</div> |
|
||||
</div> |
|
||||
|
|
||||
<style> |
|
||||
.label { |
|
||||
flex: 0; |
|
||||
} |
|
||||
|
|
||||
.inputs-group { |
|
||||
flex: 1; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,23 +0,0 @@ |
|||||
<button on:click> |
|
||||
<slot>+</slot> |
|
||||
</button> |
|
||||
|
|
||||
<style> |
|
||||
button { |
|
||||
cursor: pointer; |
|
||||
outline: none; |
|
||||
border: none; |
|
||||
border-radius: 5px; |
|
||||
min-width: 1.8rem; |
|
||||
min-height: 1.8rem; |
|
||||
padding-bottom: 10px; |
|
||||
|
|
||||
display: flex; |
|
||||
justify-content: center; |
|
||||
align-items: center; |
|
||||
|
|
||||
font-size: 1.2rem; |
|
||||
font-weight: 600; |
|
||||
color: var(--ink); |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,65 +0,0 @@ |
|||||
<script> |
|
||||
import getIcon from "./icon" |
|
||||
|
|
||||
export let icon |
|
||||
export let value |
|
||||
</script> |
|
||||
|
|
||||
<div class="select-container"> |
|
||||
{#if icon} |
|
||||
<i class={icon} /> |
|
||||
{/if} |
|
||||
<select class:adjusted={icon} on:change bind:value> |
|
||||
<slot /> |
|
||||
</select> |
|
||||
<span class="arrow"> |
|
||||
{@html getIcon('chevron-down', '24')} |
|
||||
</span> |
|
||||
</div> |
|
||||
|
|
||||
<style> |
|
||||
.select-container { |
|
||||
font-size: 14px; |
|
||||
position: relative; |
|
||||
border: var(--grey-4) 1px solid; |
|
||||
} |
|
||||
|
|
||||
.adjusted { |
|
||||
padding-left: 30px; |
|
||||
} |
|
||||
|
|
||||
i { |
|
||||
position: absolute; |
|
||||
left: 10px; |
|
||||
top: 10px; |
|
||||
} |
|
||||
|
|
||||
select { |
|
||||
height: 40px; |
|
||||
display: block; |
|
||||
font-family: sans-serif; |
|
||||
font-weight: 400; |
|
||||
font-size: 14px; |
|
||||
color: var(--ink); |
|
||||
padding: 0 40px 0px 20px; |
|
||||
width: 100%; |
|
||||
max-width: 100%; |
|
||||
box-sizing: border-box; |
|
||||
margin: 0; |
|
||||
-moz-appearance: none; |
|
||||
-webkit-appearance: none; |
|
||||
appearance: none; |
|
||||
background: var(--white); |
|
||||
} |
|
||||
|
|
||||
.arrow { |
|
||||
position: absolute; |
|
||||
right: 10px; |
|
||||
bottom: 0; |
|
||||
margin: auto; |
|
||||
width: 30px; |
|
||||
height: 30px; |
|
||||
pointer-events: none; |
|
||||
color: var(--ink); |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,33 +0,0 @@ |
|||||
<script> |
|
||||
export let text = "" |
|
||||
export let label = "" |
|
||||
export let width = "medium" |
|
||||
export let size = "small" |
|
||||
export let margin = true |
|
||||
export let infoText = "" |
|
||||
export let hasError = false |
|
||||
export let disabled = false |
|
||||
</script> |
|
||||
|
|
||||
<div class:uk-margin={margin}> |
|
||||
<label class="uk-form-label">{label}</label> |
|
||||
<div class="uk-form-controls"> |
|
||||
<input |
|
||||
data-cy={label} |
|
||||
class="budibase__input" |
|
||||
class:uk-form-danger={hasError} |
|
||||
on:change |
|
||||
bind:value={text} |
|
||||
{disabled} /> |
|
||||
</div> |
|
||||
{#if infoText} |
|
||||
<div class="info-text">{infoText}</div> |
|
||||
{/if} |
|
||||
</div> |
|
||||
|
|
||||
<style> |
|
||||
.info-text { |
|
||||
font-size: 0.7rem; |
|
||||
color: var(--secondary50); |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,16 +0,0 @@ |
|||||
<script> |
|
||||
import RecordCard from "./RecordCard.svelte" |
|
||||
|
|
||||
export let record = {} |
|
||||
</script> |
|
||||
|
|
||||
<div class="root"> |
|
||||
<div class="title">{record.name}</div> |
|
||||
<div class="inner"> |
|
||||
<div class="node-path">{record.nodeKey()}</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
|
|
||||
<style> |
|
||||
|
|
||||
</style> |
|
||||
@ -1,95 +0,0 @@ |
|||||
<script> |
|
||||
import { tick, onMount } from "svelte" |
|
||||
import { goto } from "@sveltech/routify" |
|
||||
import { store, backendUiStore } from "builderStore" |
|
||||
import api from "builderStore/api" |
|
||||
import { CheckIcon } from "../common/Icons" |
|
||||
|
|
||||
$: instances = $store.appInstances |
|
||||
|
|
||||
async function selectDatabase(database) { |
|
||||
backendUiStore.actions.database.select(database) |
|
||||
} |
|
||||
|
|
||||
async function deleteDatabase(database) { |
|
||||
const DELETE_DATABASE_URL = `/api/instances/${database.name}` |
|
||||
const response = await api.delete(DELETE_DATABASE_URL) |
|
||||
store.update(state => { |
|
||||
state.appInstances = state.appInstances.filter( |
|
||||
db => db._id !== database._id |
|
||||
) |
|
||||
return state |
|
||||
}) |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<div class="root"> |
|
||||
<ul> |
|
||||
{#each $store.appInstances as database} |
|
||||
<li> |
|
||||
<span class="icon"> |
|
||||
{#if database._id === $backendUiStore.selectedDatabase._id} |
|
||||
<CheckIcon /> |
|
||||
{/if} |
|
||||
</span> |
|
||||
<button |
|
||||
class:active={database._id === $backendUiStore.selectedDatabase._id} |
|
||||
on:click={() => { |
|
||||
$goto(`./database/${database._id}`), selectDatabase(database) |
|
||||
}}> |
|
||||
{database.name} |
|
||||
</button> |
|
||||
<i |
|
||||
class="ri-delete-bin-7-line hoverable alignment" |
|
||||
on:click={() => deleteDatabase(database)} /> |
|
||||
</li> |
|
||||
{/each} |
|
||||
</ul> |
|
||||
</div> |
|
||||
|
|
||||
<style> |
|
||||
.root { |
|
||||
font-size: 13px; |
|
||||
color: var(--ink); |
|
||||
position: relative; |
|
||||
padding-left: 20px; |
|
||||
} |
|
||||
|
|
||||
ul { |
|
||||
margin: 0; |
|
||||
padding: 0; |
|
||||
list-style: none; |
|
||||
} |
|
||||
|
|
||||
.alignment { |
|
||||
margin-left: auto; |
|
||||
padding-right: 20px; |
|
||||
} |
|
||||
|
|
||||
li { |
|
||||
margin: 0px 0px 10px 0px; |
|
||||
display: flex; |
|
||||
align-items: center; |
|
||||
} |
|
||||
|
|
||||
button { |
|
||||
margin: 0 0 0 6px; |
|
||||
padding: 0; |
|
||||
border: none; |
|
||||
font-size: 13px; |
|
||||
outline: none; |
|
||||
cursor: pointer; |
|
||||
background: rgba(0, 0, 0, 0); |
|
||||
text-rendering: optimizeLegibility; |
|
||||
} |
|
||||
|
|
||||
.active { |
|
||||
font-weight: 500; |
|
||||
} |
|
||||
|
|
||||
.icon { |
|
||||
display: inline-block; |
|
||||
width: 14px; |
|
||||
color: #333; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,82 +0,0 @@ |
|||||
<script> |
|
||||
import { onMount } from "svelte" |
|
||||
import { store, backendUiStore } from "builderStore" |
|
||||
import api from "builderStore/api" |
|
||||
import getIcon from "../common/icon" |
|
||||
import { CheckIcon } from "../common/Icons" |
|
||||
|
|
||||
const getPage = (s, name) => { |
|
||||
const props = s.pages[name] |
|
||||
return { name, props } |
|
||||
} |
|
||||
|
|
||||
$: currentAppInfo = { |
|
||||
name: $store.name, |
|
||||
} |
|
||||
|
|
||||
async function fetchUsers() { |
|
||||
const FETCH_USERS_URL = `/api/users` |
|
||||
const response = await api.get(FETCH_USERS_URL) |
|
||||
const users = await response.json() |
|
||||
backendUiStore.update(state => { |
|
||||
state.users = users |
|
||||
return state |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
onMount(fetchUsers) |
|
||||
</script> |
|
||||
|
|
||||
<div class="root"> |
|
||||
<ul> |
|
||||
{#each $backendUiStore.users as user} |
|
||||
<li> |
|
||||
<i class="ri-user-4-line" /> |
|
||||
<button class:active={user.username === $store.currentUserName}> |
|
||||
{user.name} |
|
||||
</button> |
|
||||
</li> |
|
||||
{/each} |
|
||||
</ul> |
|
||||
</div> |
|
||||
|
|
||||
<style> |
|
||||
.root { |
|
||||
padding-bottom: 10px; |
|
||||
font-size: 0.9rem; |
|
||||
color: var(--secondary50); |
|
||||
font-weight: bold; |
|
||||
position: relative; |
|
||||
padding-left: 1.8rem; |
|
||||
} |
|
||||
|
|
||||
ul { |
|
||||
margin: 0; |
|
||||
padding: 0; |
|
||||
list-style: none; |
|
||||
} |
|
||||
|
|
||||
li { |
|
||||
margin: 0.5rem 0; |
|
||||
} |
|
||||
|
|
||||
button { |
|
||||
margin: 0 0 0 6px; |
|
||||
padding: 0; |
|
||||
border: none; |
|
||||
font-size: 13px; |
|
||||
outline: none; |
|
||||
cursor: pointer; |
|
||||
background: rgba(0, 0, 0, 0); |
|
||||
} |
|
||||
|
|
||||
.active { |
|
||||
font-weight: 500; |
|
||||
} |
|
||||
|
|
||||
.icon { |
|
||||
display: inline-block; |
|
||||
width: 14px; |
|
||||
color: #333; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,111 +0,0 @@ |
|||||
<script> |
|
||||
import { store } from "builderStore" |
|
||||
import UIkit from "uikit" |
|
||||
import ActionButton from "components/common/ActionButton.svelte" |
|
||||
import ButtonGroup from "components/common/ButtonGroup.svelte" |
|
||||
import CodeMirror from "codemirror" |
|
||||
import "codemirror/mode/javascript/javascript.js" |
|
||||
|
|
||||
export let onCodeChanged |
|
||||
export let code |
|
||||
|
|
||||
export const show = () => { |
|
||||
UIkit.modal(codeModal).show() |
|
||||
} |
|
||||
|
|
||||
let codeModal |
|
||||
let editor |
|
||||
let cmInstance |
|
||||
|
|
||||
$: currentCode = code |
|
||||
$: originalCode = code |
|
||||
$: { |
|
||||
if (editor) { |
|
||||
if (!cmInstance) { |
|
||||
cmInstance = CodeMirror.fromTextArea(editor, { |
|
||||
mode: "javascript", |
|
||||
lineNumbers: false, |
|
||||
lineWrapping: true, |
|
||||
smartIndent: true, |
|
||||
matchBrackets: true, |
|
||||
readOnly: false, |
|
||||
}) |
|
||||
cmInstance.on("change", () => (currentCode = cmInstance.getValue())) |
|
||||
} |
|
||||
cmInstance.focus() |
|
||||
cmInstance.setValue(code || "") |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
const cancel = () => { |
|
||||
UIkit.modal(codeModal).hide() |
|
||||
currentCode = originalCode |
|
||||
} |
|
||||
|
|
||||
const save = () => { |
|
||||
originalCode = currentCode |
|
||||
onCodeChanged(currentCode) |
|
||||
UIkit.modal(codeModal).hide() |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<div bind:this={codeModal} uk-modal> |
|
||||
<div class="uk-modal-dialog" uk-overflow-auto> |
|
||||
|
|
||||
<div class="uk-modal-header"> |
|
||||
<h3>Code</h3> |
|
||||
</div> |
|
||||
|
|
||||
<div class="uk-modal-body uk-form-horizontal"> |
|
||||
|
|
||||
<p> |
|
||||
Use the code box below to control how this component is displayed, with |
|
||||
javascript. |
|
||||
</p> |
|
||||
|
|
||||
<div> |
|
||||
<div class="editor-code-surround"> |
|
||||
function(render, context, state, route) {'{'} |
|
||||
</div> |
|
||||
<div class="editor"> |
|
||||
<textarea bind:this={editor} /> |
|
||||
</div> |
|
||||
<div class="editor-code-surround">{'}'}</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
|
|
||||
<div class="uk-modal-footer"> |
|
||||
<ButtonGroup> |
|
||||
<ActionButton primary on:click={save}>Save</ActionButton> |
|
||||
<ActionButton alert on:click={cancel}>Close</ActionButton> |
|
||||
</ButtonGroup> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
|
|
||||
<style> |
|
||||
h3 { |
|
||||
text-transform: uppercase; |
|
||||
font-size: 13px; |
|
||||
font-weight: 700; |
|
||||
color: #8997ab; |
|
||||
margin-bottom: 10px; |
|
||||
} |
|
||||
|
|
||||
p { |
|
||||
font-size: 13px; |
|
||||
color: #333; |
|
||||
margin-top: 0; |
|
||||
} |
|
||||
|
|
||||
.editor { |
|
||||
border-style: dotted; |
|
||||
border-width: 1px; |
|
||||
border-color: gainsboro; |
|
||||
padding: 10px 30px; |
|
||||
} |
|
||||
|
|
||||
.editor-code-surround { |
|
||||
font-family: "Courier New", Courier, monospace; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,320 +0,0 @@ |
|||||
<script> |
|
||||
import { onMount, createEventDispatcher } from "svelte" |
|
||||
import { fade } from "svelte/transition" |
|
||||
import Swatch from "./Swatch.svelte" |
|
||||
import CheckedBackground from "./CheckedBackground.svelte" |
|
||||
import { buildStyle } from "./helpers.js" |
|
||||
import { |
|
||||
getColorFormat, |
|
||||
convertToHSVA, |
|
||||
convertHsvaToFormat, |
|
||||
} from "./utils.js" |
|
||||
import Slider from "./Slider.svelte" |
|
||||
import Palette from "./Palette.svelte" |
|
||||
import ButtonGroup from "./ButtonGroup.svelte" |
|
||||
import Input from "./Input.svelte" |
|
||||
import Portal from "./Portal.svelte" |
|
||||
|
|
||||
export let value = "#3ec1d3ff" |
|
||||
export let open = false |
|
||||
export let swatches = [] //TODO: Safe swatches - limit to 12. warn in console |
|
||||
export let disableSwatches = false |
|
||||
export let format = "hexa" |
|
||||
export let style = "" |
|
||||
export let pickerHeight = 0 |
|
||||
export let pickerWidth = 0 |
|
||||
|
|
||||
let colorPicker = null |
|
||||
let adder = null |
|
||||
|
|
||||
let h = null |
|
||||
let s = null |
|
||||
let v = null |
|
||||
let a = null |
|
||||
|
|
||||
const dispatch = createEventDispatcher() |
|
||||
|
|
||||
onMount(() => { |
|
||||
if (!swatches.length > 0) { |
|
||||
//Don't use locally stored recent colors if swatches have been passed as props |
|
||||
getRecentColors() |
|
||||
} |
|
||||
|
|
||||
if (colorPicker) { |
|
||||
colorPicker.focus() |
|
||||
} |
|
||||
|
|
||||
if (format) { |
|
||||
convertAndSetHSVA() |
|
||||
} |
|
||||
}) |
|
||||
|
|
||||
function getRecentColors() { |
|
||||
let colorStore = localStorage.getItem("cp:recent-colors") |
|
||||
if (colorStore) { |
|
||||
swatches = JSON.parse(colorStore) |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function handleEscape(e) { |
|
||||
if (open && e.key === "Escape") { |
|
||||
open = false |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function setRecentColor(color) { |
|
||||
if (swatches.length === 12) { |
|
||||
swatches.splice(0, 1) |
|
||||
} |
|
||||
if (!swatches.includes(color)) { |
|
||||
swatches = [...swatches, color] |
|
||||
localStorage.setItem("cp:recent-colors", JSON.stringify(swatches)) |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function convertAndSetHSVA() { |
|
||||
let hsva = convertToHSVA(value, format) |
|
||||
setHSVA(hsva) |
|
||||
} |
|
||||
|
|
||||
function setHSVA([hue, sat, val, alpha]) { |
|
||||
h = hue |
|
||||
s = sat |
|
||||
v = val |
|
||||
a = alpha |
|
||||
} |
|
||||
|
|
||||
//fired by choosing a color from the palette |
|
||||
function setSaturationAndValue({ detail }) { |
|
||||
s = detail.s |
|
||||
v = detail.v |
|
||||
value = convertHsvaToFormat([h, s, v, a], format) |
|
||||
dispatchValue() |
|
||||
} |
|
||||
|
|
||||
function setHue({ color, isDrag }) { |
|
||||
h = color |
|
||||
value = convertHsvaToFormat([h, s, v, a], format) |
|
||||
if (!isDrag) { |
|
||||
dispatchValue() |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function setAlpha({ color, isDrag }) { |
|
||||
a = color === "1.00" ? "1" : color |
|
||||
value = convertHsvaToFormat([h, s, v, a], format) |
|
||||
if (!isDrag) { |
|
||||
dispatchValue() |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function dispatchValue() { |
|
||||
dispatch("change", value) |
|
||||
} |
|
||||
|
|
||||
function changeFormatAndConvert(f) { |
|
||||
format = f |
|
||||
value = convertHsvaToFormat([h, s, v, a], format) |
|
||||
} |
|
||||
|
|
||||
function handleColorInput(text) { |
|
||||
let format = getColorFormat(text) |
|
||||
if (format) { |
|
||||
value = text |
|
||||
convertAndSetHSVA() |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function dispatchInputChange() { |
|
||||
if (format) { |
|
||||
dispatchValue() |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function addSwatch() { |
|
||||
if (format) { |
|
||||
dispatch("addswatch", value) |
|
||||
setRecentColor(value) |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function removeSwatch(idx) { |
|
||||
let removedSwatch = swatches.splice(idx, 1) |
|
||||
swatches = swatches |
|
||||
dispatch("removeswatch", removedSwatch) |
|
||||
localStorage.setItem("cp:recent-colors", JSON.stringify(swatches)) |
|
||||
} |
|
||||
|
|
||||
function applySwatch(color) { |
|
||||
if (value !== color) { |
|
||||
format = getColorFormat(color) |
|
||||
if (format) { |
|
||||
value = color |
|
||||
convertAndSetHSVA() |
|
||||
dispatchValue() |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
$: border = v > 90 && s < 5 ? "1px dashed #dedada" : "" |
|
||||
$: selectedColorStyle = buildStyle({ background: value, border }) |
|
||||
$: shrink = swatches.length > 0 |
|
||||
</script> |
|
||||
|
|
||||
<Portal> |
|
||||
<div |
|
||||
class="colorpicker-container" |
|
||||
transition:fade |
|
||||
bind:this={colorPicker} |
|
||||
{style} |
|
||||
tabindex="0" |
|
||||
on:keydown={handleEscape} |
|
||||
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={selectedColorStyle} /> |
|
||||
</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>+</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> |
|
||||
</Portal> |
|
||||
|
|
||||
<style> |
|
||||
.colorpicker-container { |
|
||||
position: absolute; |
|
||||
outline: none; |
|
||||
z-index: 3; |
|
||||
display: flex; |
|
||||
font-size: 11px; |
|
||||
font-weight: 400; |
|
||||
flex-direction: column; |
|
||||
margin: 5px 0px; |
|
||||
height: auto; |
|
||||
width: 220px; |
|
||||
background: #ffffff; |
|
||||
border-radius: 2px; |
|
||||
box-shadow: 0 0.15em 1.5em 0 rgba(0, 0, 0, 0.1), |
|
||||
0 0 1em 0 rgba(0, 0, 0, 0.03); |
|
||||
} |
|
||||
|
|
||||
.palette-panel { |
|
||||
flex: 1; |
|
||||
} |
|
||||
|
|
||||
.control-panel { |
|
||||
flex: 1; |
|
||||
display: flex; |
|
||||
flex-direction: column; |
|
||||
padding: 8px; |
|
||||
background: white; |
|
||||
border: 1px solid #d2d2d2; |
|
||||
color: #777373; |
|
||||
} |
|
||||
|
|
||||
.alpha-hue-panel { |
|
||||
display: grid; |
|
||||
grid-template-columns: 25px 1fr; |
|
||||
grid-gap: 15px; |
|
||||
justify-content: center; |
|
||||
align-items: center; |
|
||||
} |
|
||||
|
|
||||
.selected-color { |
|
||||
width: 30px; |
|
||||
height: 30px; |
|
||||
border-radius: 50%; |
|
||||
} |
|
||||
|
|
||||
.swatch-panel { |
|
||||
flex: 0 0 15px; |
|
||||
display: flex; |
|
||||
flex-flow: row wrap; |
|
||||
justify-content: flex-start; |
|
||||
padding: 0 5px; |
|
||||
max-height: 56px; |
|
||||
} |
|
||||
|
|
||||
.adder { |
|
||||
flex: 1; |
|
||||
height: 20px; |
|
||||
display: flex; |
|
||||
transition: flex 0.5s; |
|
||||
justify-content: center; |
|
||||
align-items: center; |
|
||||
background: #f1f3f4; |
|
||||
cursor: pointer; |
|
||||
border: 1px solid #d4d4d4; |
|
||||
border-radius: 8px; |
|
||||
margin-left: 5px; |
|
||||
margin-top: 3px; |
|
||||
font-weight: 500; |
|
||||
} |
|
||||
|
|
||||
.shrink { |
|
||||
flex: 0 0 20px; |
|
||||
} |
|
||||
|
|
||||
.format-input-panel { |
|
||||
display: flex; |
|
||||
flex-direction: column; |
|
||||
justify-content: center; |
|
||||
padding-top: 3px; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,157 +0,0 @@ |
|||||
<script> |
|
||||
import Colorpicker from "./Colorpicker.svelte" |
|
||||
import CheckedBackground from "./CheckedBackground.svelte" |
|
||||
import { createEventDispatcher, beforeUpdate } from "svelte" |
|
||||
|
|
||||
import { buildStyle } from "./helpers.js" |
|
||||
import { fade } from "svelte/transition" |
|
||||
import { getColorFormat } from "./utils.js" |
|
||||
|
|
||||
export let value = "#3ec1d3ff" |
|
||||
export let swatches = [] |
|
||||
export let disableSwatches = false |
|
||||
export let open = false |
|
||||
export let width = "25px" |
|
||||
export let height = "25px" |
|
||||
|
|
||||
let format = "hexa" |
|
||||
let dimensions = { top: 0, bottom: 0, right: 0, left: 0 } |
|
||||
let positionSide = "top" |
|
||||
let colorPreview = null |
|
||||
|
|
||||
let previewHeight = null |
|
||||
let previewWidth = null |
|
||||
let pickerWidth = 0 |
|
||||
let pickerHeight = 0 |
|
||||
|
|
||||
let errorMsg = null |
|
||||
|
|
||||
const dispatch = createEventDispatcher() |
|
||||
|
|
||||
beforeUpdate(() => { |
|
||||
format = getColorFormat(value) |
|
||||
if (!format) { |
|
||||
errorMsg = `Colorpicker - ${value} is an unknown color format. Please use a hex, rgb or hsl value` |
|
||||
console.error(errorMsg) |
|
||||
} else { |
|
||||
errorMsg = null |
|
||||
} |
|
||||
}) |
|
||||
|
|
||||
function openColorpicker(event) { |
|
||||
if (colorPreview) { |
|
||||
open = true |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function onColorChange(color) { |
|
||||
value = color.detail |
|
||||
dispatch("change", color.detail) |
|
||||
} |
|
||||
|
|
||||
$: if (open && colorPreview) { |
|
||||
const { |
|
||||
top: spaceAbove, |
|
||||
width, |
|
||||
bottom, |
|
||||
right, |
|
||||
left, |
|
||||
} = colorPreview.getBoundingClientRect() |
|
||||
|
|
||||
const spaceBelow = window.innerHeight - bottom |
|
||||
const previewCenter = previewWidth / 2 |
|
||||
|
|
||||
let y, x |
|
||||
|
|
||||
if (spaceAbove > spaceBelow) { |
|
||||
positionSide = "bottom" |
|
||||
y = window.innerHeight - spaceAbove |
|
||||
} else { |
|
||||
positionSide = "top" |
|
||||
y = bottom |
|
||||
} |
|
||||
|
|
||||
x = left + previewCenter - pickerWidth / 2 |
|
||||
|
|
||||
dimensions = { [positionSide]: y.toFixed(1), left: x.toFixed(1) } |
|
||||
} |
|
||||
|
|
||||
$: previewStyle = buildStyle({ width, height, background: value }) |
|
||||
$: errorPreviewStyle = buildStyle({ width, height }) |
|
||||
$: pickerStyle = buildStyle({ |
|
||||
[positionSide]: `${dimensions[positionSide]}px`, |
|
||||
left: `${dimensions.left}px`, |
|
||||
}) |
|
||||
</script> |
|
||||
|
|
||||
<div class="color-preview-container"> |
|
||||
{#if !errorMsg} |
|
||||
<CheckedBackground borderRadius="3px" backgroundSize="8px"> |
|
||||
<div |
|
||||
bind:this={colorPreview} |
|
||||
bind:clientHeight={previewHeight} |
|
||||
bind:clientWidth={previewWidth} |
|
||||
class="color-preview" |
|
||||
style={previewStyle} |
|
||||
on:click={openColorpicker} /> |
|
||||
</CheckedBackground> |
|
||||
|
|
||||
{#if open} |
|
||||
<Colorpicker |
|
||||
style={pickerStyle} |
|
||||
on:change={onColorChange} |
|
||||
on:addswatch |
|
||||
on:removeswatch |
|
||||
bind:format |
|
||||
bind:value |
|
||||
bind:pickerHeight |
|
||||
bind:pickerWidth |
|
||||
bind:open |
|
||||
{swatches} |
|
||||
{disableSwatches} /> |
|
||||
<div on:click|self={() => (open = false)} class="overlay" /> |
|
||||
{/if} |
|
||||
{:else} |
|
||||
<div class="color-preview preview-error" style={errorPreviewStyle}> |
|
||||
<span>×</span> |
|
||||
</div> |
|
||||
{/if} |
|
||||
</div> |
|
||||
|
|
||||
<style> |
|
||||
.color-preview-container { |
|
||||
display: flex; |
|
||||
flex-flow: row nowrap; |
|
||||
height: fit-content; |
|
||||
} |
|
||||
|
|
||||
.color-preview { |
|
||||
cursor: pointer; |
|
||||
border-radius: 3px; |
|
||||
border: 1px solid #dedada; |
|
||||
} |
|
||||
|
|
||||
.preview-error { |
|
||||
background: #cccccc; |
|
||||
color: #808080; |
|
||||
text-align: center; |
|
||||
font-size: 18px; |
|
||||
cursor: not-allowed; |
|
||||
} |
|
||||
|
|
||||
/* .picker-container { |
|
||||
position: absolute; |
|
||||
z-index: 3; |
|
||||
width: fit-content; |
|
||||
height: fit-content; |
|
||||
} */ |
|
||||
|
|
||||
.overlay { |
|
||||
position: fixed; |
|
||||
top: 0; |
|
||||
bottom: 0; |
|
||||
left: 0; |
|
||||
right: 0; |
|
||||
z-index: 2; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,37 +0,0 @@ |
|||||
<script> |
|
||||
import { onMount } from "svelte" |
|
||||
|
|
||||
export let target = document.body |
|
||||
|
|
||||
let targetEl |
|
||||
let portal |
|
||||
let componentInstance |
|
||||
|
|
||||
onMount(() => { |
|
||||
if (typeof target === "string") { |
|
||||
targetEl = document.querySelector(target) |
|
||||
// Force exit |
|
||||
if (targetEl === null) { |
|
||||
return () => {} |
|
||||
} |
|
||||
} else if (target instanceof HTMLElement) { |
|
||||
targetEl = target |
|
||||
} else { |
|
||||
throw new TypeError( |
|
||||
`Unknown target type: ${typeof target}. Allowed types: String (CSS selector), HTMLElement.` |
|
||||
) |
|
||||
} |
|
||||
|
|
||||
portal = document.createElement("div") |
|
||||
targetEl.appendChild(portal) |
|
||||
portal.appendChild(componentInstance) |
|
||||
|
|
||||
return () => { |
|
||||
targetEl.removeChild(portal) |
|
||||
} |
|
||||
}) |
|
||||
</script> |
|
||||
|
|
||||
<div bind:this={componentInstance}> |
|
||||
<slot /> |
|
||||
</div> |
|
||||
@ -1,59 +0,0 @@ |
|||||
<script> |
|
||||
import { searchAllComponents } from "./pagesParsing/searchComponents" |
|
||||
import { store } from "../builderStore" |
|
||||
|
|
||||
export let onComponentChosen = () => {} |
|
||||
|
|
||||
let phrase = "" |
|
||||
|
|
||||
components = $store.components |
|
||||
|
|
||||
$: filteredComponents = !phrase ? [] : searchAllComponents(components, phrase) |
|
||||
</script> |
|
||||
|
|
||||
<div class="root"> |
|
||||
|
|
||||
<form on:submit|preventDefault class="uk-search uk-search-large"> |
|
||||
<span uk-search-icon /> |
|
||||
<input |
|
||||
class="uk-search-input" |
|
||||
type="search" |
|
||||
placeholder="Based on component..." |
|
||||
bind:value={phrase} /> |
|
||||
</form> |
|
||||
|
|
||||
<div> |
|
||||
{#each filteredComponents as component} |
|
||||
<div class="component" on:click={() => onComponentChosen(component)}> |
|
||||
<div class="title">{component.name}</div> |
|
||||
<div class="description">{component.description}</div> |
|
||||
</div> |
|
||||
{/each} |
|
||||
</div> |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
<style> |
|
||||
.component { |
|
||||
padding: 5px; |
|
||||
border-style: solid; |
|
||||
border-width: 0 0 1px 0; |
|
||||
border-color: var(--grey-1); |
|
||||
cursor: pointer; |
|
||||
} |
|
||||
|
|
||||
.component:hover { |
|
||||
background-color: var(--primary10); |
|
||||
} |
|
||||
|
|
||||
.component > .title { |
|
||||
font-size: 13pt; |
|
||||
color: var(--ink); |
|
||||
} |
|
||||
|
|
||||
.component > .description { |
|
||||
font-size: 10pt; |
|
||||
color: var(--blue); |
|
||||
font-style: italic; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,90 +0,0 @@ |
|||||
<script> |
|
||||
import PropsView from "./PropsView.svelte" |
|
||||
import { store } from "../builderStore" |
|
||||
import Textbox from "../common/Textbox.svelte" |
|
||||
import Button from "../common/Button.svelte" |
|
||||
import { LayoutIcon, PaintIcon, TerminalIcon } from "../common/Icons/" |
|
||||
|
|
||||
import { cloneDeep, join, split, last } from "lodash/fp" |
|
||||
import { assign } from "lodash" |
|
||||
|
|
||||
$: component = $store.currentPreviewItem |
|
||||
$: componentInfo = $store.currentComponentInfo |
|
||||
$: components = $store.components |
|
||||
|
|
||||
const updateComponent = doChange => doChange(cloneDeep(component)) |
|
||||
|
|
||||
const onPropsChanged = newProps => { |
|
||||
updateComponent(newComponent => assign(newComponent.props, newProps)) |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<div class="root"> |
|
||||
|
|
||||
<ul> |
|
||||
<li> |
|
||||
<button> |
|
||||
<PaintIcon /> |
|
||||
</button> |
|
||||
</li> |
|
||||
<li> |
|
||||
<button> |
|
||||
<LayoutIcon /> |
|
||||
</button> |
|
||||
</li> |
|
||||
<li> |
|
||||
<button> |
|
||||
<TerminalIcon /> |
|
||||
</button> |
|
||||
</li> |
|
||||
</ul> |
|
||||
|
|
||||
<div class="component-props-container"> |
|
||||
<PropsView {componentInfo} {onPropsChanged} /> |
|
||||
</div> |
|
||||
</div> |
|
||||
|
|
||||
<style> |
|
||||
.root { |
|
||||
height: 100%; |
|
||||
display: flex; |
|
||||
flex-direction: column; |
|
||||
} |
|
||||
|
|
||||
.title > div:nth-child(1) { |
|
||||
grid-column-start: name; |
|
||||
color: var(--ink); |
|
||||
} |
|
||||
|
|
||||
.title > div:nth-child(2) { |
|
||||
grid-column-start: actions; |
|
||||
} |
|
||||
|
|
||||
.component-props-container { |
|
||||
flex: 1 1 auto; |
|
||||
overflow-y: auto; |
|
||||
} |
|
||||
|
|
||||
ul { |
|
||||
list-style: none; |
|
||||
display: flex; |
|
||||
padding: 0; |
|
||||
} |
|
||||
|
|
||||
li { |
|
||||
margin-right: 20px; |
|
||||
background: none; |
|
||||
border-radius: 5px; |
|
||||
width: 45px; |
|
||||
height: 45px; |
|
||||
} |
|
||||
|
|
||||
li button { |
|
||||
width: 100%; |
|
||||
height: 100%; |
|
||||
background: none; |
|
||||
border: none; |
|
||||
border-radius: 5px; |
|
||||
padding: 13px; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,170 +0,0 @@ |
|||||
<script> |
|
||||
import InputGroup from "../common/Inputs/InputGroup.svelte" |
|
||||
import LayoutTemplateControls from "./LayoutTemplateControls.svelte" |
|
||||
|
|
||||
export let onStyleChanged = () => {} |
|
||||
export let component |
|
||||
|
|
||||
const tbrl = [ |
|
||||
{ placeholder: "T" }, |
|
||||
{ placeholder: "R" }, |
|
||||
{ placeholder: "B" }, |
|
||||
{ placeholder: "L" }, |
|
||||
] |
|
||||
|
|
||||
const se = [{ placeholder: "START" }, { placeholder: "END" }] |
|
||||
|
|
||||
const single = [{ placeholder: "" }] |
|
||||
|
|
||||
$: layout = { |
|
||||
...component._styles.position, |
|
||||
...component._styles.layout, |
|
||||
} |
|
||||
|
|
||||
$: layouts = { |
|
||||
templaterows: ["Grid Rows", single], |
|
||||
templatecolumns: ["Grid Columns", single], |
|
||||
} |
|
||||
|
|
||||
$: display = { |
|
||||
direction: ["Direction", single], |
|
||||
align: ["Align", single], |
|
||||
justify: ["Justify", single], |
|
||||
} |
|
||||
|
|
||||
$: positions = { |
|
||||
column: ["Column", se], |
|
||||
row: ["Row", se], |
|
||||
} |
|
||||
|
|
||||
$: spacing = { |
|
||||
margin: ["Margin", tbrl, "small"], |
|
||||
padding: ["Padding", tbrl, "small"], |
|
||||
} |
|
||||
|
|
||||
$: size = { |
|
||||
height: ["Height", single], |
|
||||
width: ["Width", single], |
|
||||
} |
|
||||
|
|
||||
$: zindex = { |
|
||||
zindex: ["Z-Index", single], |
|
||||
} |
|
||||
|
|
||||
const newValue = n => Array(n).fill("") |
|
||||
</script> |
|
||||
|
|
||||
<h3>Layout</h3> |
|
||||
<div class="layout-pos"> |
|
||||
{#each Object.entries(display) as [key, [name, meta, size]] (component._id + key)} |
|
||||
<div class="grid"> |
|
||||
<h5>{name}:</h5> |
|
||||
<LayoutTemplateControls |
|
||||
onStyleChanged={_value => onStyleChanged('layout', key, _value)} |
|
||||
values={layout[key] || newValue(meta.length)} |
|
||||
propertyName={name} |
|
||||
{meta} |
|
||||
{size} |
|
||||
type="text" /> |
|
||||
</div> |
|
||||
{/each} |
|
||||
</div> |
|
||||
|
|
||||
<!-- <h4>Positioning</h4> |
|
||||
<div class="layout-pos"> |
|
||||
{#each Object.entries(positions) as [key, [name, meta, size]] (component._id + key)} |
|
||||
<div class="grid"> |
|
||||
<h5>{name}:</h5> |
|
||||
<InputGroup |
|
||||
onStyleChanged={_value => onStyleChanged('position', key, _value)} |
|
||||
values={layout[key] || newValue(meta.length)} |
|
||||
{meta} |
|
||||
{size} /> |
|
||||
</div> |
|
||||
{/each} |
|
||||
</div> --> |
|
||||
|
|
||||
<h3>Spacing</h3> |
|
||||
<div class="layout-spacing"> |
|
||||
{#each Object.entries(spacing) as [key, [name, meta, size]] (component._id + key)} |
|
||||
<div class="grid"> |
|
||||
<h5>{name}:</h5> |
|
||||
<InputGroup |
|
||||
onStyleChanged={_value => onStyleChanged('position', key, _value)} |
|
||||
values={layout[key] || newValue(meta.length)} |
|
||||
{meta} |
|
||||
{size} |
|
||||
type="text" /> |
|
||||
</div> |
|
||||
{/each} |
|
||||
</div> |
|
||||
|
|
||||
<h3>Size</h3> |
|
||||
<div class="layout-layer"> |
|
||||
{#each Object.entries(size) as [key, [name, meta, size]] (component._id + key)} |
|
||||
<div class="grid"> |
|
||||
<h5>{name}:</h5> |
|
||||
<InputGroup |
|
||||
onStyleChanged={_value => onStyleChanged('position', key, _value)} |
|
||||
values={layout[key] || newValue(meta.length)} |
|
||||
type="text" |
|
||||
{meta} |
|
||||
{size} /> |
|
||||
</div> |
|
||||
{/each} |
|
||||
</div> |
|
||||
|
|
||||
<h3>Order</h3> |
|
||||
<div class="layout-layer"> |
|
||||
{#each Object.entries(zindex) as [key, [name, meta, size]] (component._id + key)} |
|
||||
<div class="grid"> |
|
||||
<h5>{name}:</h5> |
|
||||
<InputGroup |
|
||||
onStyleChanged={_value => onStyleChanged('position', key, _value)} |
|
||||
values={layout[key] || newValue(meta.length)} |
|
||||
{meta} |
|
||||
{size} /> |
|
||||
</div> |
|
||||
{/each} |
|
||||
</div> |
|
||||
|
|
||||
<style> |
|
||||
h3 { |
|
||||
text-transform: uppercase; |
|
||||
font-size: 13px; |
|
||||
font-weight: 600; |
|
||||
color: var(--ink); |
|
||||
opacity: 0.6; |
|
||||
margin-bottom: 10px; |
|
||||
} |
|
||||
|
|
||||
h4 { |
|
||||
text-transform: uppercase; |
|
||||
font-size: 10px; |
|
||||
font-weight: 600; |
|
||||
color: var(--ink); |
|
||||
opacity: 0.4; |
|
||||
margin-bottom: 10px; |
|
||||
} |
|
||||
|
|
||||
h5 { |
|
||||
font-size: 13px; |
|
||||
font-weight: 400; |
|
||||
color: var(--ink); |
|
||||
opacity: 0.8; |
|
||||
padding-top: 13px; |
|
||||
margin-bottom: 0; |
|
||||
} |
|
||||
|
|
||||
div > div { |
|
||||
display: grid; |
|
||||
grid-template-rows: 1fr; |
|
||||
grid-gap: 10px; |
|
||||
height: 40px; |
|
||||
margin-bottom: 15px; |
|
||||
} |
|
||||
|
|
||||
.grid { |
|
||||
grid-template-columns: 70px 2fr; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,33 +0,0 @@ |
|||||
<script> |
|
||||
import { onMount } from "svelte" |
|
||||
export let value = "" |
|
||||
export let onChange = value => {} |
|
||||
export let options = [] |
|
||||
export let initialValue = "" |
|
||||
export let styleBindingProperty = "" |
|
||||
|
|
||||
const handleStyleBind = value => |
|
||||
!!styleBindingProperty ? { style: `${styleBindingProperty}: ${value}` } : {} |
|
||||
|
|
||||
$: isOptionsObject = options.every(o => typeof o === "object") |
|
||||
|
|
||||
onMount(() => { |
|
||||
if (!value && !!initialValue) { |
|
||||
value = initialValue |
|
||||
} |
|
||||
}) |
|
||||
</script> |
|
||||
|
|
||||
<select {value} on:change={ev => onChange(ev.target.value)}> |
|
||||
{#if isOptionsObject} |
|
||||
{#each options as { value, label }} |
|
||||
<option {...handleStyleBind(value || label)} value={value || label}> |
|
||||
{label} |
|
||||
</option> |
|
||||
{/each} |
|
||||
{:else} |
|
||||
{#each options as value} |
|
||||
<option {...handleStyleBind(value)} {value}>{value}</option> |
|
||||
{/each} |
|
||||
{/if} |
|
||||
</select> |
|
||||
@ -1,65 +0,0 @@ |
|||||
<script> |
|
||||
import Textbox from "components/common/Textbox.svelte" |
|
||||
import Dropdown from "components/common/Dropdown.svelte" |
|
||||
import Button from "components/common/Button.svelte" |
|
||||
import { store } from "builderStore" |
|
||||
import { isRootComponent } from "./pagesParsing/searchComponents" |
|
||||
import { pipe } from "components/common/core" |
|
||||
import { filter, find, concat } from "lodash/fp" |
|
||||
|
|
||||
const notSelectedComponent = { name: "(none selected)" } |
|
||||
|
|
||||
$: page = $store.pages[$store.currentPageName] |
|
||||
$: title = page.index.title |
|
||||
$: components = pipe($store.components, [ |
|
||||
filter(store => !isRootComponent($store)), |
|
||||
concat([notSelectedComponent]), |
|
||||
]) |
|
||||
$: entryComponent = components[page.appBody] || notSelectedComponent |
|
||||
|
|
||||
const save = () => { |
|
||||
if (!title || !entryComponent || entryComponent === notSeletedComponent) |
|
||||
return |
|
||||
const page = { |
|
||||
index: { |
|
||||
title, |
|
||||
}, |
|
||||
appBody: entryComponent.name, |
|
||||
} |
|
||||
store.savePage(page) |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<div class="root"> |
|
||||
|
|
||||
<h3>{$store.currentPageName}</h3> |
|
||||
|
|
||||
<form on:submit|preventDefault class="uk-form-horizontal"> |
|
||||
<Textbox bind:text={title} label="Title" hasError={!title} /> |
|
||||
<div class="help-text"> |
|
||||
The title of your page, displayed in the bowser tab |
|
||||
</div> |
|
||||
<Dropdown |
|
||||
label="App Entry Component" |
|
||||
options={components} |
|
||||
bind:selected={entryComponent} |
|
||||
textMember={v => v.name} /> |
|
||||
|
|
||||
<div class="help-text"> |
|
||||
The component that will be loaded into the body of the page |
|
||||
</div> |
|
||||
<div style="margin-top: 20px" /> |
|
||||
<Button on:click={save}>Save</Button> |
|
||||
</form> |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
<style> |
|
||||
.root { |
|
||||
padding: 15px; |
|
||||
} |
|
||||
.help-text { |
|
||||
color: var(--grey-2); |
|
||||
font-size: 10pt; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,46 +0,0 @@ |
|||||
<script> |
|
||||
import { store } from "builderStore" |
|
||||
import Checkbox from "../common/Checkbox.svelte" |
|
||||
import Textbox from "../common/Textbox.svelte" |
|
||||
import Dropdown from "../common/Dropdown.svelte" |
|
||||
import StateBindingControl from "./StateBindingControl.svelte" |
|
||||
|
|
||||
export let index |
|
||||
export let prop_name |
|
||||
export let prop_value |
|
||||
export let prop_definition = {} |
|
||||
</script> |
|
||||
|
|
||||
<div class="root"> |
|
||||
{#if prop_definition.type !== 'event'} |
|
||||
<h5>{prop_name}</h5> |
|
||||
<StateBindingControl |
|
||||
value={prop_value} |
|
||||
type={prop_definition.type || prop_definition} |
|
||||
options={prop_definition.options} |
|
||||
styleBindingProperty={prop_definition.styleBindingProperty} |
|
||||
onChanged={v => store.setComponentProp(prop_name, v)} /> |
|
||||
{/if} |
|
||||
</div> |
|
||||
|
|
||||
<style> |
|
||||
.root { |
|
||||
height: 40px; |
|
||||
margin-bottom: 15px; |
|
||||
display: grid; |
|
||||
grid-template-rows: 1fr; |
|
||||
grid-template-columns: 70px 1fr; |
|
||||
grid-gap: 10px; |
|
||||
align-items: baseline; |
|
||||
} |
|
||||
|
|
||||
h5 { |
|
||||
word-wrap: break-word; |
|
||||
font-size: 13px; |
|
||||
font-weight: 400; |
|
||||
color: var(--ink); |
|
||||
opacity: 0.8; |
|
||||
padding-top: 13px; |
|
||||
margin-bottom: 0; |
|
||||
} |
|
||||
</style> |
|
||||
@ -0,0 +1,11 @@ |
|||||
|
<script> |
||||
|
/* |
||||
|
This file exists because of how we pass this control to the |
||||
|
properties panel - via a JS reference, not using svelte tags |
||||
|
... checkout the use of Input in propertyCategories to see what i mean |
||||
|
*/ |
||||
|
import { Input } from "@budibase/bbui" |
||||
|
export let name, value, placeholder, type |
||||
|
</script> |
||||
|
|
||||
|
<Input {name} {value} {placeholder} {type} thin on:change /> |
||||
@ -1,54 +0,0 @@ |
|||||
<script> |
|
||||
import { some, includes, filter } from "lodash/fp" |
|
||||
import Textbox from "../common/Textbox.svelte" |
|
||||
import Dropdown from "../common/Dropdown.svelte" |
|
||||
import PropControl from "./PropControl.svelte" |
|
||||
import IconButton from "../common/IconButton.svelte" |
|
||||
|
|
||||
export let component |
|
||||
export let components |
|
||||
|
|
||||
let errors = [] |
|
||||
const props_to_ignore = ["_component", "_children", "_styles", "_code", "_id"] |
|
||||
|
|
||||
$: componentDef = components[component._component] |
|
||||
</script> |
|
||||
|
|
||||
<div class="root"> |
|
||||
|
|
||||
<form on:submit|preventDefault class="uk-form-stacked form-root"> |
|
||||
{#if componentDef} |
|
||||
{#each Object.entries(componentDef.props) as [prop_name, prop_def], index} |
|
||||
{#if prop_def !== 'event'} |
|
||||
<div class="prop-container"> |
|
||||
<PropControl |
|
||||
{prop_name} |
|
||||
prop_value={component[prop_name]} |
|
||||
prop_definition={prop_def} |
|
||||
{index} |
|
||||
disabled={false} /> |
|
||||
|
|
||||
</div> |
|
||||
{/if} |
|
||||
{/each} |
|
||||
{/if} |
|
||||
</form> |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
<style> |
|
||||
.root { |
|
||||
font-size: 10pt; |
|
||||
width: 100%; |
|
||||
} |
|
||||
|
|
||||
.form-root { |
|
||||
display: flex; |
|
||||
flex-wrap: wrap; |
|
||||
} |
|
||||
|
|
||||
.prop-container { |
|
||||
flex: 1 1 auto; |
|
||||
min-width: 250px; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,63 +0,0 @@ |
|||||
<script> |
|
||||
import { backendUiStore } from "builderStore" |
|
||||
import IconButton from "../common/IconButton.svelte" |
|
||||
import Input from "../common/Input.svelte" |
|
||||
|
|
||||
export let value = "" |
|
||||
export let onChanged = () => {} |
|
||||
export let type = "" |
|
||||
export let options = [] |
|
||||
export let styleBindingProperty = "" |
|
||||
|
|
||||
$: bindOptionToStyle = !!styleBindingProperty |
|
||||
</script> |
|
||||
|
|
||||
<div class="unbound-container"> |
|
||||
{#if type === 'bool'} |
|
||||
<div> |
|
||||
<IconButton |
|
||||
icon={value == true ? 'check-square' : 'square'} |
|
||||
size="19" |
|
||||
on:click={() => onChanged(!value)} /> |
|
||||
</div> |
|
||||
{:else if type === 'models'} |
|
||||
<select |
|
||||
class="uk-select uk-form-small" |
|
||||
bind:value |
|
||||
on:change={() => { |
|
||||
onChanged(value) |
|
||||
}}> |
|
||||
{#each $backendUiStore.models || [] as option} |
|
||||
<option value={option}>{option.name}</option> |
|
||||
{/each} |
|
||||
</select> |
|
||||
{:else if type === 'options' || type === 'models'} |
|
||||
<select |
|
||||
class="uk-select uk-form-small" |
|
||||
{value} |
|
||||
on:change={ev => onChanged(ev.target.value)}> |
|
||||
{#each options || [] as option} |
|
||||
{#if bindOptionToStyle} |
|
||||
<option style={`${styleBindingProperty}: ${option};`} value={option}> |
|
||||
{option} |
|
||||
</option> |
|
||||
{:else} |
|
||||
<option value={option}>{option}</option> |
|
||||
{/if} |
|
||||
{/each} |
|
||||
</select> |
|
||||
{/if} |
|
||||
</div> |
|
||||
|
|
||||
<style> |
|
||||
.unbound-container { |
|
||||
display: flex; |
|
||||
} |
|
||||
|
|
||||
.bound-header > div:nth-child(1) { |
|
||||
flex: 1 0 auto; |
|
||||
width: 30px; |
|
||||
color: var(--secondary50); |
|
||||
padding-left: 5px; |
|
||||
} |
|
||||
</style> |
|
||||
File diff suppressed because it is too large
@ -1,6 +0,0 @@ |
|||||
.DS_Store |
|
||||
node_modules |
|
||||
yarn.lock |
|
||||
package-lock.json |
|
||||
dist/* |
|
||||
public/build |
|
||||
@ -1,3 +0,0 @@ |
|||||
* |
|
||||
!dist/* |
|
||||
!components.json |
|
||||
@ -1,33 +0,0 @@ |
|||||
*Psst — looking for an app template? Go here --> [sveltejs/template](https://github.com/sveltejs/template)* |
|
||||
|
|
||||
--- |
|
||||
|
|
||||
# component-template |
|
||||
|
|
||||
A base for building shareable Svelte components. Clone it with [degit](https://github.com/Rich-Harris/degit): |
|
||||
|
|
||||
```bash |
|
||||
npx degit sveltejs/component-template my-new-component |
|
||||
cd my-new-component |
|
||||
npm install # or yarn |
|
||||
``` |
|
||||
|
|
||||
Your component's source code lives in `src/index.html`. |
|
||||
|
|
||||
TODO |
|
||||
|
|
||||
* [ ] some firm opinions about the best way to test components |
|
||||
* [ ] update `degit` so that it automates some of the setup work |
|
||||
|
|
||||
|
|
||||
## Setting up |
|
||||
|
|
||||
* Run `npm init` (or `yarn init`) |
|
||||
* Replace this README with your own |
|
||||
|
|
||||
|
|
||||
## Consuming components |
|
||||
|
|
||||
Your package.json has a `"svelte"` field pointing to `src/index.html`, which allows Svelte apps to import the source code directly, if they are using a bundler plugin like [rollup-plugin-svelte](https://github.com/rollup/rollup-plugin-svelte) or [svelte-loader](https://github.com/sveltejs/svelte-loader) (where [`resolve.mainFields`](https://webpack.js.org/configuration/resolve/#resolve-mainfields) in your webpack config includes `"svelte"`). **This is recommended.** |
|
||||
|
|
||||
For everyone else, `npm run build` will bundle your component's source code into a plain JavaScript module (`index.mjs`) and a UMD script (`index.js`). This will happen automatically when you publish your component to npm, courtesy of the `prepublishOnly` hook in package.json. |
|
||||
@ -1,458 +0,0 @@ |
|||||
{ |
|
||||
"_lib": "./dist/index.js", |
|
||||
"_templates": { |
|
||||
"indexDatatable": { |
|
||||
"description": "Datatable based on an Index", |
|
||||
"component": "Datatable" |
|
||||
}, |
|
||||
"recordForm": { |
|
||||
"description": "Form for saving a record", |
|
||||
"component": "Form" |
|
||||
} |
|
||||
}, |
|
||||
"Body1": { |
|
||||
"name": "Body1", |
|
||||
"description": "Sets the font properties as Roboto Body 1", |
|
||||
"props": { |
|
||||
"text": "string" |
|
||||
}, |
|
||||
"tags": [] |
|
||||
}, |
|
||||
"Body2": { |
|
||||
"name": "Body2", |
|
||||
"description": "Sets the font properties as Roboto Body 2", |
|
||||
"props": { |
|
||||
"text": "string" |
|
||||
}, |
|
||||
"tags": [] |
|
||||
}, |
|
||||
"Select": { |
|
||||
"name": "Select", |
|
||||
"description": "A material design select (aka Dropdown, aka Combobox)", |
|
||||
"props": { |
|
||||
"onSelect": "event", |
|
||||
"value": "string", |
|
||||
"width": "string", |
|
||||
"variant": { |
|
||||
"type": "options", |
|
||||
"options": [ |
|
||||
"filled", "outlined" |
|
||||
] |
|
||||
}, |
|
||||
"disabled": "bool", |
|
||||
"required": "bool", |
|
||||
"label": "string", |
|
||||
"helperText": "string", |
|
||||
"persistent": "bool" |
|
||||
} |
|
||||
}, |
|
||||
"List": { |
|
||||
"name": "List", |
|
||||
"description": "A Material Design List Component.", |
|
||||
"props": { |
|
||||
"onSelect": "event", |
|
||||
"singleSelection": "bool", |
|
||||
"variant": { |
|
||||
"type": "options", |
|
||||
"options": ["one-line", "two-line"], |
|
||||
"default": "one-line" |
|
||||
}, |
|
||||
"inputElement": { |
|
||||
"type": "options", |
|
||||
"options": ["None", "Radiobutton", "Checkbox"], |
|
||||
"default": "None" |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
"ListItem": { |
|
||||
"name": "ListItem", |
|
||||
"description": "Use as item in a 'List' or 'Select' component", |
|
||||
"props": { |
|
||||
"value": "string", |
|
||||
"text": "string", |
|
||||
"secondaryText": "string", |
|
||||
"leadingIcon": "string", |
|
||||
"trailingIcon": "string", |
|
||||
"disabled": "bool", |
|
||||
"dividerAfter": "bool" |
|
||||
} |
|
||||
}, |
|
||||
"Button": { |
|
||||
"name": "Button", |
|
||||
"children": false, |
|
||||
"description": "A Material Design button with different variations. It renders as an anchor if href is passed to it.", |
|
||||
"props": { |
|
||||
"onClick": "event", |
|
||||
"variant": { |
|
||||
"type": "options", |
|
||||
"options": ["text", "raised", "unelevated", "outlined"], |
|
||||
"default": "text" |
|
||||
}, |
|
||||
"colour": { |
|
||||
"type": "options", |
|
||||
"options": ["primary", "secondary"], |
|
||||
"default": "primary" |
|
||||
}, |
|
||||
"size": { |
|
||||
"type": "options", |
|
||||
"options": ["small", "medium", "large"], |
|
||||
"default": "medium" |
|
||||
}, |
|
||||
"href": "string", |
|
||||
"icon": "string", |
|
||||
"trailingIcon": "bool", |
|
||||
"fullwidth": "bool", |
|
||||
"text": "string", |
|
||||
"disabled": "bool" |
|
||||
}, |
|
||||
"tags": [] |
|
||||
}, |
|
||||
"Caption": { |
|
||||
"name": "Caption", |
|
||||
"description": "Sets the font properties as Roboto Caption", |
|
||||
"props": { |
|
||||
"text": "string" |
|
||||
}, |
|
||||
"tags": [] |
|
||||
}, |
|
||||
"BasicCard": { |
|
||||
"name": "BasicCard", |
|
||||
"description": "This is a basic card", |
|
||||
"props": { |
|
||||
"heading": "string", |
|
||||
"subheading": "string", |
|
||||
"content": "string", |
|
||||
"imageUrl": "string", |
|
||||
"button1Text": "string", |
|
||||
"button2Text": "string", |
|
||||
"cardClick": "event", |
|
||||
"button1Click": "event", |
|
||||
"button2Click": "event" |
|
||||
} |
|
||||
}, |
|
||||
"Card": { |
|
||||
"name": "Card", |
|
||||
"description": "A Material Card container. Accepts CardHeader, CardBody and CardFooter as possible children", |
|
||||
"props": { |
|
||||
"width": {"type": "string", "default": "350px"}, |
|
||||
"height": "string", |
|
||||
"variant": { |
|
||||
"type": "options", |
|
||||
"options": ["standard", "outlined"], |
|
||||
"default": "outlined" |
|
||||
} |
|
||||
} |
|
||||
}, |
|
||||
"CardBody": { |
|
||||
"name": "CardBody", |
|
||||
"description": "A Material CardBody component. Contains the main content of a Material Card component", |
|
||||
"props": { |
|
||||
"onClick": "event" |
|
||||
} |
|
||||
}, |
|
||||
"CardImage": { |
|
||||
"name": "CardImage", |
|
||||
"description": "An image component for the Material Card component", |
|
||||
"props": { |
|
||||
"displayHorizontal": "bool", |
|
||||
"url": "string", |
|
||||
"title": "string", |
|
||||
"subtitle": "string" |
|
||||
} |
|
||||
}, |
|
||||
"CardHeader": { |
|
||||
"name": "CardHeader", |
|
||||
"description": "Displays a icon, title and subtitle above main body of the Material Card component", |
|
||||
"props": { |
|
||||
"title": "string", |
|
||||
"subtitle": "string", |
|
||||
"icon": "string" |
|
||||
} |
|
||||
}, |
|
||||
"CardFooter": { |
|
||||
"name": "CardFooter", |
|
||||
"description": "Displays buttons / icon buttons as actions for the Material Card component", |
|
||||
"props": { |
|
||||
"padding": "string" |
|
||||
} |
|
||||
}, |
|
||||
"Checkbox": { |
|
||||
"name": "Checkbox", |
|
||||
"description": "A Material Design checkbox. Supports aligning label before or after checkbox.", |
|
||||
"props": { |
|
||||
"onClick": "event", |
|
||||
"id": "string", |
|
||||
"label": "string", |
|
||||
"disabled": "bool", |
|
||||
"alignEnd": "bool", |
|
||||
"indeterminate": "bool", |
|
||||
"checked": "bool" |
|
||||
}, |
|
||||
"tags": [] |
|
||||
}, |
|
||||
"Checkboxgroup": { |
|
||||
"name": "Checkboxgroup", |
|
||||
"description": "A group of material design checkboxes. Supports row and column orientation.", |
|
||||
"props": { |
|
||||
"onChange": "event", |
|
||||
"label":"string", |
|
||||
"orientation": { |
|
||||
"type": "options", |
|
||||
"options": ["row", "column"], |
|
||||
"default": "row" |
|
||||
}, |
|
||||
"disabled": "bool", |
|
||||
"alignEnd": "bool" |
|
||||
} |
|
||||
}, |
|
||||
"Datatable": { |
|
||||
"name": "Datatable", |
|
||||
"description": "A Material Design component to represent tabular data.", |
|
||||
"props": { |
|
||||
"onLoad":"event" |
|
||||
}, |
|
||||
"tags": [] |
|
||||
}, |
|
||||
"DatatableHead": { |
|
||||
"name": "DatatableHead", |
|
||||
"description": "Material Design <thead>.", |
|
||||
"props": {} |
|
||||
}, |
|
||||
"DatatableCell": { |
|
||||
"name": "DatatableCell", |
|
||||
"description": "Material Design <td>.", |
|
||||
"props": {} |
|
||||
}, |
|
||||
"DatatableBody": { |
|
||||
"name": "DatatableBody", |
|
||||
"description": "Material Design <tbody>.", |
|
||||
"props": {} |
|
||||
}, |
|
||||
"DatatableRow": { |
|
||||
"name": "DatatableRow", |
|
||||
"description": "Material Design <tr>.", |
|
||||
"props": {} |
|
||||
}, |
|
||||
"DatePicker": { |
|
||||
"name": "DatePicker", |
|
||||
"description": "Material Design DatePicker", |
|
||||
"props": { |
|
||||
"date": "string", |
|
||||
"label": "string", |
|
||||
"onSelect": "event" |
|
||||
}, |
|
||||
"tags": [] |
|
||||
}, |
|
||||
"H1": { |
|
||||
"name": "H1", |
|
||||
"description": "Sets the font properties as Roboto Headline1", |
|
||||
"props": { |
|
||||
"text": "string" |
|
||||
}, |
|
||||
"tags": [] |
|
||||
}, |
|
||||
"H2": { |
|
||||
"name": "H2", |
|
||||
"description": "Sets the font properties as Roboto Headline2", |
|
||||
"props": { |
|
||||
"text": "string" |
|
||||
}, |
|
||||
"tags": [] |
|
||||
}, |
|
||||
"H3": { |
|
||||
"name": "H3", |
|
||||
"description": "Sets the font properties as Roboto Headline3", |
|
||||
"props": { |
|
||||
"text": "string" |
|
||||
}, |
|
||||
"tags": [] |
|
||||
}, |
|
||||
"H4": { |
|
||||
"name": "H4", |
|
||||
"description": "Sets the font properties as Roboto Headline4", |
|
||||
"props": { |
|
||||
"text": "string" |
|
||||
}, |
|
||||
"tags": [] |
|
||||
}, |
|
||||
"H5": { |
|
||||
"name": "H5", |
|
||||
"description": "Sets the font properties as Roboto Headline5", |
|
||||
"props": { |
|
||||
"text": "string" |
|
||||
}, |
|
||||
"tags": [] |
|
||||
}, |
|
||||
"H6": { |
|
||||
"name": "H6", |
|
||||
"description": "Sets the font properties as Roboto Headline6", |
|
||||
"props": { |
|
||||
"text": "string" |
|
||||
}, |
|
||||
"tags": [] |
|
||||
}, |
|
||||
"IconButton": { |
|
||||
"name": "IconButton", |
|
||||
"description": "An icon button component", |
|
||||
"props": { |
|
||||
"onClick": "event", |
|
||||
"disabled": "bool", |
|
||||
"href": "string", |
|
||||
"icon": "string", |
|
||||
"size": { |
|
||||
"type":"options", |
|
||||
"options": ["small", "medium", "large"], |
|
||||
"default": "medium" |
|
||||
} |
|
||||
}, |
|
||||
"tags": [] |
|
||||
}, |
|
||||
"Label": { |
|
||||
"name": "Label", |
|
||||
"description": "A simple label component that displays its text in the standard Roboto Material Design font", |
|
||||
"props": { |
|
||||
"text": "string", |
|
||||
"bold": "bool" |
|
||||
}, |
|
||||
"tags": [] |
|
||||
}, |
|
||||
"Menu": { |
|
||||
"name": "Menu", |
|
||||
"description": "A Material Design menu component. Anchor to other components to create a pop-out menu.", |
|
||||
"props": { |
|
||||
"onSelect": "event", |
|
||||
"width": "string", |
|
||||
"open": "bool", |
|
||||
"useFixedPosition": "bool", |
|
||||
"absolutePositionX": "number", |
|
||||
"absolutePositionY": "number" |
|
||||
} |
|
||||
}, |
|
||||
"Overline": { |
|
||||
"name": "Overline", |
|
||||
"description": "Sets the font properties as Roboto Overline", |
|
||||
"props": { |
|
||||
"text": "string" |
|
||||
}, |
|
||||
"tags": [] |
|
||||
}, |
|
||||
"Radiobutton": { |
|
||||
"name": "Radiobutton", |
|
||||
"description": "A Material Design radiobutton. Supports aligning label before or after radiobutton.", |
|
||||
"props": { |
|
||||
"onClick": "event", |
|
||||
"id": "string", |
|
||||
"label": "string", |
|
||||
"name": "string", |
|
||||
"disabled": "bool", |
|
||||
"alignEnd": "bool" |
|
||||
}, |
|
||||
"tags": [] |
|
||||
}, |
|
||||
"Radiobuttongroup": { |
|
||||
"name": "Radiobuttongroup", |
|
||||
"description": "A Material Design Radiobutton group. Supports row and column orientation.", |
|
||||
"props": { |
|
||||
"onChange": "event", |
|
||||
"label": "string", |
|
||||
"name": "string", |
|
||||
"orientation": { |
|
||||
"type": "options", |
|
||||
"options": ["row", "column"], |
|
||||
"default": "row" |
|
||||
}, |
|
||||
"fullwidth": "bool", |
|
||||
"alignEnd": "bool", |
|
||||
"disabled": "bool" |
|
||||
} |
|
||||
}, |
|
||||
"Sub1": { |
|
||||
"name": "Sub1", |
|
||||
"description": "Sets the font properties as Roboto Subtitle1", |
|
||||
"props": { |
|
||||
"text": "string" |
|
||||
}, |
|
||||
"tags": [] |
|
||||
}, |
|
||||
"Sub2": { |
|
||||
"name": "Sub2", |
|
||||
"description": "Sets the font properties as Roboto Subtitle2", |
|
||||
"props": { |
|
||||
"text": "string" |
|
||||
}, |
|
||||
"tags": [] |
|
||||
}, |
|
||||
"Textfield": { |
|
||||
"name": "Textfield", |
|
||||
"description": "A Material Design textfield with multiple variants. Can also be converted to a text area / multine text field.", |
|
||||
"props": { |
|
||||
"onChange": "event", |
|
||||
"value": "string", |
|
||||
"label": "string", |
|
||||
"variant": { |
|
||||
"type": "options", |
|
||||
"options": ["standard", "outlined", "filled"], |
|
||||
"default": "standard" |
|
||||
}, |
|
||||
"disabled": "bool", |
|
||||
"fullwidth": "bool", |
|
||||
"colour": { |
|
||||
"type": "options", |
|
||||
"options": ["primary", "secondary"], |
|
||||
"default": "primary" |
|
||||
}, |
|
||||
"size":{ |
|
||||
"type": "options", |
|
||||
"options": ["small", "medium", "large"], |
|
||||
"default": "medium" |
|
||||
}, |
|
||||
"type": { |
|
||||
"type": "options", |
|
||||
"options": ["text", "password"], |
|
||||
"default": "text" |
|
||||
}, |
|
||||
"required": "bool", |
|
||||
"minLength": "number", |
|
||||
"maxLength": "number", |
|
||||
"helperText": "string", |
|
||||
"placeholder": "string", |
|
||||
"icon": "string", |
|
||||
"trailingIcon": "bool", |
|
||||
"textarea": "bool", |
|
||||
"persistent": "bool" |
|
||||
}, |
|
||||
"tags": [] |
|
||||
}, |
|
||||
"Switch": { |
|
||||
"name": "Switch", |
|
||||
"description": "A material design switch component", |
|
||||
"props": { |
|
||||
"alignEnd": "bool", |
|
||||
"disabled": "bool", |
|
||||
"checked": "bool", |
|
||||
"label": "string", |
|
||||
"id": "string" |
|
||||
}, |
|
||||
"tags": [] |
|
||||
}, |
|
||||
"Slider": { |
|
||||
"name": "Slider", |
|
||||
"description": "A material design slider component", |
|
||||
"props": { |
|
||||
"variant": { |
|
||||
"type": "options", |
|
||||
"options": ["continuous", "discrete"], |
|
||||
"default": "continuous" |
|
||||
}, |
|
||||
"showTicks": "bool", |
|
||||
"min": "number", |
|
||||
"max": "number", |
|
||||
"value": "number", |
|
||||
"step": "number", |
|
||||
"label": "string", |
|
||||
"disabled": "bool" |
|
||||
}, |
|
||||
"tags": [] |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
@ -1,59 +0,0 @@ |
|||||
{ |
|
||||
"name": "@budibase/materialdesign-components", |
|
||||
"svelte": "src/index.svelte", |
|
||||
"main": "dist/index.js", |
|
||||
"module": "dist/index.js", |
|
||||
"scripts": { |
|
||||
"build": "rollup -c", |
|
||||
"prepublishOnly": "npm run build", |
|
||||
"testbuild": "rollup -w -c rollup.testconfig.js", |
|
||||
"dev": "run-p start:dev testbuild", |
|
||||
"start:dev": "sirv public --single --dev", |
|
||||
"dev:builder": "rollup -cw" |
|
||||
}, |
|
||||
"devDependencies": { |
|
||||
"@budibase/client": "^0.1.17", |
|
||||
"@budibase/standard-components": "^0.1.17", |
|
||||
"@material/button": "^4.0.0", |
|
||||
"@material/checkbox": "^4.0.0", |
|
||||
"@material/data-table": "4.0.0", |
|
||||
"@material/dialog": "4.0.0", |
|
||||
"@material/form-field": "^4.0.0", |
|
||||
"@material/icon-button": "4.0.0", |
|
||||
"@material/list": "4.0.0", |
|
||||
"@material/menu": "4.0.0", |
|
||||
"@material/radio": "^4.0.0", |
|
||||
"@material/select": "4.0.0", |
|
||||
"@material/slider": "4.0.0", |
|
||||
"@material/switch": "4.0.0", |
|
||||
"@material/textfield": "^4.0.0", |
|
||||
"@nx-js/compiler-util": "^2.0.0", |
|
||||
"bcryptjs": "^2.4.3", |
|
||||
"date-fns": "^2.10.0", |
|
||||
"fs-extra": "^8.1.0", |
|
||||
"lodash": "^4.17.15", |
|
||||
"npm-run-all": "^4.1.5", |
|
||||
"rollup": "^1.11.0", |
|
||||
"rollup-plugin-alias": "^2.2.0", |
|
||||
"rollup-plugin-commonjs": "^10.0.2", |
|
||||
"rollup-plugin-json": "^4.0.0", |
|
||||
"rollup-plugin-livereload": "^1.0.1", |
|
||||
"rollup-plugin-node-resolve": "^5.0.0", |
|
||||
"rollup-plugin-postcss": "^2.0.5", |
|
||||
"rollup-plugin-svelte": "^5.0.0", |
|
||||
"rollup-plugin-terser": "^5.1.1", |
|
||||
"sass": "^1.25.1-test.1", |
|
||||
"shortid": "^2.2.15", |
|
||||
"sirv-cli": "^0.4.4", |
|
||||
"svelte": "^3.12.1" |
|
||||
}, |
|
||||
"keywords": [ |
|
||||
"svelte" |
|
||||
], |
|
||||
"version": "0.1.17", |
|
||||
"license": "MIT", |
|
||||
"gitHead": "284cceb9b703c38566c6e6363c022f79a08d5691", |
|
||||
"dependencies": { |
|
||||
"@material/card": "4.0.0" |
|
||||
} |
|
||||
} |
|
||||
@ -1,16 +0,0 @@ |
|||||
<!doctype html> |
|
||||
<html> |
|
||||
<head> |
|
||||
<meta charset='utf8'> |
|
||||
<meta name='viewport' content='width=device-width'> |
|
||||
|
|
||||
<title>Budibase-Material Design</title> |
|
||||
<link rel='icon' type='image/png' href='/favicon.png'> |
|
||||
<link rel='stylesheet' href='/build/bundle.css'> |
|
||||
|
|
||||
</head> |
|
||||
|
|
||||
<body> |
|
||||
<script src='/build/bundle.js'></script> |
|
||||
</body> |
|
||||
</html> |
|
||||
@ -1,50 +0,0 @@ |
|||||
import svelte from "rollup-plugin-svelte" |
|
||||
import postcss from "rollup-plugin-postcss" |
|
||||
import resolve from "rollup-plugin-node-resolve" |
|
||||
import commonjs from "rollup-plugin-commonjs" |
|
||||
|
|
||||
const postcssOptions = () => ({ |
|
||||
extensions: [".scss", ".sass"], |
|
||||
extract: false, |
|
||||
minimize: true, |
|
||||
use: [ |
|
||||
[ |
|
||||
"sass", |
|
||||
{ |
|
||||
includePaths: ["./node_modules"], |
|
||||
}, |
|
||||
], |
|
||||
], |
|
||||
}) |
|
||||
|
|
||||
const coreExternal = ["shortid"] |
|
||||
|
|
||||
export default { |
|
||||
input: "src/index.js", |
|
||||
output: [ |
|
||||
{ |
|
||||
file: "dist/index.js", |
|
||||
format: "esm", |
|
||||
name: "budibaseStandardComponents", |
|
||||
sourcemap: true, |
|
||||
}, |
|
||||
], |
|
||||
plugins: [ |
|
||||
svelte({ |
|
||||
hydratable: true, |
|
||||
}), |
|
||||
resolve({ |
|
||||
preferBuiltins: true, |
|
||||
browser: true, |
|
||||
dedupe: importee => { |
|
||||
return coreExternal.includes(importee) |
|
||||
}, |
|
||||
}), |
|
||||
commonjs({ |
|
||||
namedExports: { |
|
||||
shortid: ["generate"], |
|
||||
}, |
|
||||
}), |
|
||||
postcss(postcssOptions()), |
|
||||
], |
|
||||
} |
|
||||
@ -1,166 +0,0 @@ |
|||||
import svelte from "rollup-plugin-svelte" |
|
||||
import resolve from "rollup-plugin-node-resolve" |
|
||||
import commonjs from "rollup-plugin-commonjs" |
|
||||
import livereload from "rollup-plugin-livereload" |
|
||||
import { terser } from "rollup-plugin-terser" |
|
||||
import json from "rollup-plugin-json" |
|
||||
import alias from "rollup-plugin-alias" |
|
||||
import postcss from "rollup-plugin-postcss" |
|
||||
import path from "path" |
|
||||
|
|
||||
const aliases = { |
|
||||
resolve: [".js", ".svelte"], |
|
||||
entries: [ |
|
||||
// { find: "@BBMD", replacement: path.resolve(__dirname, "dist/index.js") },
|
|
||||
{ find: "@BBMD", replacement: path.resolve(__dirname, "src/index.js") }, |
|
||||
], |
|
||||
} |
|
||||
|
|
||||
const postcssOptions = () => ({ |
|
||||
extensions: [".scss", ".sass"], |
|
||||
extract: false, |
|
||||
minimize: true, |
|
||||
use: [ |
|
||||
[ |
|
||||
"sass", |
|
||||
{ |
|
||||
includePaths: ["./node_modules"], |
|
||||
}, |
|
||||
], |
|
||||
], |
|
||||
}) |
|
||||
|
|
||||
const production = !process.env.ROLLUP_WATCH |
|
||||
|
|
||||
const lodash_fp_exports = [ |
|
||||
"find", |
|
||||
"isUndefined", |
|
||||
"split", |
|
||||
"max", |
|
||||
"last", |
|
||||
"union", |
|
||||
"reduce", |
|
||||
"isObject", |
|
||||
"cloneDeep", |
|
||||
"some", |
|
||||
"isArray", |
|
||||
"map", |
|
||||
"filter", |
|
||||
"keys", |
|
||||
"isFunction", |
|
||||
"isEmpty", |
|
||||
"countBy", |
|
||||
"join", |
|
||||
"includes", |
|
||||
"flatten", |
|
||||
"constant", |
|
||||
"first", |
|
||||
"intersection", |
|
||||
"take", |
|
||||
"has", |
|
||||
"mapValues", |
|
||||
"isString", |
|
||||
"isBoolean", |
|
||||
"isNull", |
|
||||
"isNumber", |
|
||||
"isObjectLike", |
|
||||
"isDate", |
|
||||
"clone", |
|
||||
"values", |
|
||||
"keyBy", |
|
||||
"isNaN", |
|
||||
"isInteger", |
|
||||
"toNumber", |
|
||||
] |
|
||||
|
|
||||
const lodash_exports = [ |
|
||||
"flow", |
|
||||
"head", |
|
||||
"find", |
|
||||
"each", |
|
||||
"tail", |
|
||||
"findIndex", |
|
||||
"startsWith", |
|
||||
"dropRight", |
|
||||
"takeRight", |
|
||||
"trim", |
|
||||
"split", |
|
||||
"replace", |
|
||||
"merge", |
|
||||
"assign", |
|
||||
] |
|
||||
|
|
||||
const coreExternal = [ |
|
||||
"lodash", |
|
||||
"lodash/fp", |
|
||||
"date-fns", |
|
||||
"lunr", |
|
||||
"safe-buffer", |
|
||||
"shortid", |
|
||||
"@nx-js/compiler-util", |
|
||||
"bcryptjs", |
|
||||
] |
|
||||
|
|
||||
export default { |
|
||||
input: "src/Test/testMain.js", |
|
||||
output: { |
|
||||
sourcemap: true, |
|
||||
format: "iife", |
|
||||
name: "app", |
|
||||
file: "public/build/bundle.js", |
|
||||
globals: { |
|
||||
crypto: "crypto", |
|
||||
}, |
|
||||
}, |
|
||||
plugins: [ |
|
||||
alias(aliases), |
|
||||
svelte({ |
|
||||
// enable run-time checks when not in production
|
|
||||
dev: !production, |
|
||||
// we'll extract any component CSS out into
|
|
||||
// a separate file — better for performance
|
|
||||
css: css => { |
|
||||
css.write("public/build/bundle.css") |
|
||||
}, |
|
||||
|
|
||||
hydratable: true, |
|
||||
}), |
|
||||
|
|
||||
// If you have external dependencies installed from
|
|
||||
// npm, you'll most likely need these plugins. In
|
|
||||
// some cases you'll need additional configuration —
|
|
||||
// consult the documentation for details:
|
|
||||
// https://github.com/rollup/rollup-plugin-commonjs
|
|
||||
resolve({ |
|
||||
browser: true, |
|
||||
dedupe: importee => { |
|
||||
return ( |
|
||||
importee === "svelte" || |
|
||||
importee.startsWith("svelte/") || |
|
||||
coreExternal.includes(importee) |
|
||||
) |
|
||||
}, |
|
||||
preferBuiltins: true, |
|
||||
}), |
|
||||
commonjs({ |
|
||||
namedExports: { |
|
||||
"lodash/fp": lodash_fp_exports, |
|
||||
lodash: lodash_exports, |
|
||||
shortid: ["generate"], |
|
||||
}, |
|
||||
}), |
|
||||
json(), |
|
||||
|
|
||||
// Watch the `public` directory and refresh the
|
|
||||
// browser on changes when not in production
|
|
||||
!production && livereload("public"), |
|
||||
|
|
||||
// If we're building for production (npm run build
|
|
||||
// instead of npm run dev), minify
|
|
||||
production && terser(), |
|
||||
postcss(postcssOptions()), |
|
||||
], |
|
||||
watch: { |
|
||||
clearScreen: false, |
|
||||
}, |
|
||||
} |
|
||||
@ -1,74 +0,0 @@ |
|||||
<script> |
|
||||
import { onMount } from "svelte" |
|
||||
import Icon from "../Common/Icon.svelte" |
|
||||
import ripple from "../Common/Ripple.js" |
|
||||
import ClassBuilder from "../ClassBuilder.js" |
|
||||
|
|
||||
const cb = new ClassBuilder("button", ["primary", "medium", "text"]) |
|
||||
|
|
||||
export let _bb |
|
||||
export let onClick |
|
||||
|
|
||||
export let variant = "text" |
|
||||
export let colour = "primary" |
|
||||
export let size = "medium" |
|
||||
|
|
||||
export let href = "" |
|
||||
export let icon = "" |
|
||||
export let trailingIcon = false |
|
||||
export let fullwidth = false |
|
||||
|
|
||||
export let text = "" |
|
||||
export let disabled = false |
|
||||
|
|
||||
onMount(() => { |
|
||||
let ctx = _bb.getContext("BBMD:button:context") |
|
||||
extras = [ctx] |
|
||||
}) |
|
||||
|
|
||||
let extras = "" |
|
||||
let modifiers = {} |
|
||||
let customs = { size, colour } |
|
||||
|
|
||||
if (!href) modifiers = { variant } |
|
||||
|
|
||||
$: props = { modifiers, customs, extras } |
|
||||
|
|
||||
$: blockClasses = cb.build({ props }) |
|
||||
const labelClass = cb.elem("label") |
|
||||
|
|
||||
const clicked = () => _bb.call(onClick) |
|
||||
|
|
||||
$: renderLeadingIcon = !!icon && !trailingIcon |
|
||||
$: renderTrailingIcon = !!icon && trailingIcon |
|
||||
</script> |
|
||||
|
|
||||
{#if href} |
|
||||
<a class={blockClasses} {href} on:click={clicked}> |
|
||||
<span class={labelClass}>{text}</span> |
|
||||
</a> |
|
||||
{:else} |
|
||||
<button |
|
||||
use:ripple={{ colour }} |
|
||||
class={blockClasses} |
|
||||
class:fullwidth |
|
||||
{disabled} |
|
||||
on:click={clicked}> |
|
||||
{#if renderLeadingIcon} |
|
||||
<Icon context="button__icon" {icon} /> |
|
||||
{/if} |
|
||||
<span class={labelClass}>{text}</span> |
|
||||
{#if renderTrailingIcon} |
|
||||
<Icon context="button__icon" {icon} /> |
|
||||
{/if} |
|
||||
</button> |
|
||||
{/if} |
|
||||
|
|
||||
<style> |
|
||||
.mdc-button:not(.fullwidth) { |
|
||||
width: fit-content; |
|
||||
} |
|
||||
.fullwidth { |
|
||||
width: 100%; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,5 +0,0 @@ |
|||||
@import "@material/button/mdc-button.scss"; |
|
||||
@import "@material/ripple/mdc-ripple.scss"; |
|
||||
@import "./mixins.scss"; |
|
||||
|
|
||||
@include bbmd-button-styles(); |
|
||||
@ -1,39 +0,0 @@ |
|||||
@import "@material/feature-targeting/functions"; |
|
||||
@import "@material/feature-targeting/mixins"; |
|
||||
|
|
||||
@mixin bbmd-button-styles($query: mdc-feature-all()) { |
|
||||
$feat-structure: mdc-feature-create-target($query, structure); |
|
||||
|
|
||||
.bbmd-mdc-button--size-large { |
|
||||
@include button-sizing($feat-structure, 21px, 40px, 15px); |
|
||||
} |
|
||||
|
|
||||
.bbmd-mdc-button--size-small { |
|
||||
@include button-sizing($feat-structure, 9px, 32px, 13px); |
|
||||
} |
|
||||
|
|
||||
.bbmd-mdc-button--colour-secondary { |
|
||||
//no feature target as relying on theme variable custom property |
|
||||
@include mdc-button-ink-color(secondary); |
|
||||
|
|
||||
&.mdc-button--raised, |
|
||||
&.mdc-button--unelevated { |
|
||||
@include mdc-button-container-fill-color(secondary); |
|
||||
@include mdc-button-ink-color(on-secondary); |
|
||||
} |
|
||||
|
|
||||
&.mdc-button--outlined { |
|
||||
@include mdc-button-outline-color(secondary); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
@mixin button-sizing($feat, $padding, $height, $fontSize) { |
|
||||
@include mdc-feature-targets($feat) { |
|
||||
padding: 0px $padding; |
|
||||
height: $height; |
|
||||
} |
|
||||
> .mdc-button__label { |
|
||||
font-size: $fontSize; |
|
||||
} |
|
||||
} |
|
||||
@ -1,2 +0,0 @@ |
|||||
import "./_index.scss" |
|
||||
export { default as Button } from "./Button.svelte" |
|
||||
@ -1,67 +0,0 @@ |
|||||
<script> |
|
||||
export let heading = "" |
|
||||
export let subheading = "" |
|
||||
export let content = "" |
|
||||
export let imageUrl = "" |
|
||||
export let button1Text = "" |
|
||||
export let button2Text = "" |
|
||||
export let cardClick = () => {} |
|
||||
export let button1Click = () => {} |
|
||||
export let button2Click = () => {} |
|
||||
|
|
||||
$: showImage = !!imageUrl |
|
||||
$: showButton1 = !!button1Text |
|
||||
$: showButton2 = !!button2Text |
|
||||
$: showButtons = !!showButton1 && !!showButton2 |
|
||||
</script> |
|
||||
|
|
||||
<div class="mdc-card" on:click={cardClick}> |
|
||||
<div class="mdc-card__primary-action demo-card__primary-action" tabindex="0"> |
|
||||
{#if showImage} |
|
||||
<div |
|
||||
class="mdc-card__media mdc-card__media--16-9 demo-card__media" |
|
||||
style="background-image: url("{imageUrl}");" /> |
|
||||
{/if} |
|
||||
<div class="pad"> |
|
||||
<div class="demo-card__primary"> |
|
||||
<h2 class="demo-card__title mdc-typography mdc-typography--headline6"> |
|
||||
{heading} |
|
||||
</h2> |
|
||||
<h3 |
|
||||
class="demo-card__subtitle mdc-typography mdc-typography--subtitle2"> |
|
||||
{subheading} |
|
||||
</h3> |
|
||||
</div> |
|
||||
<div class="demo-card__secondary mdc-typography mdc-typography--body2"> |
|
||||
{content} |
|
||||
</div> |
|
||||
|
|
||||
</div> |
|
||||
</div> |
|
||||
{#if showButtons} |
|
||||
<div class="mdc-card__actions"> |
|
||||
<div class="mdc-card__action-buttons"> |
|
||||
{#if showButton1} |
|
||||
<button class="mdc-button mdc-card__action mdc-card__action--button"> |
|
||||
<span class="mdc-button__ripple" on:click={button1Click} /> |
|
||||
{button1Text} |
|
||||
</button> |
|
||||
{/if} |
|
||||
{#if showButton2} |
|
||||
<button |
|
||||
class="mdc-button mdc-card__action mdc-card__action--button" |
|
||||
on:click={button2Click}> |
|
||||
<span class="mdc-button__ripple" /> |
|
||||
{button2Text} |
|
||||
</button> |
|
||||
{/if} |
|
||||
</div> |
|
||||
</div> |
|
||||
{/if} |
|
||||
</div> |
|
||||
|
|
||||
<style> |
|
||||
.pad { |
|
||||
padding: 10px; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,39 +0,0 @@ |
|||||
<script> |
|
||||
import CardHeader from "./CardHeader.svelte" |
|
||||
import CardBody from "./CardBody.svelte" |
|
||||
import CardImage from "./CardImage.svelte" |
|
||||
import CardFooter from "./CardFooter.svelte" |
|
||||
import { H2, H6, Body2 } from "../Typography" |
|
||||
import { Button } from "../Button" |
|
||||
import { IconButton } from "../IconButton" |
|
||||
import ClassBuilder from "../ClassBuilder.js" |
|
||||
|
|
||||
export let width = "350px" |
|
||||
export let height = "auto" |
|
||||
export let variant = "standard" |
|
||||
|
|
||||
export let _bb |
|
||||
let card |
|
||||
|
|
||||
const cb = new ClassBuilder("card", ["standard"]) |
|
||||
|
|
||||
$: modifiers = { variant } |
|
||||
$: props = { modifiers } |
|
||||
$: cardClass = cb.build({ props }) |
|
||||
|
|
||||
$: safeWidth = width !== "auto" && !/px$/.test(width) ? `${width}px` : width |
|
||||
|
|
||||
$: safeHeight = |
|
||||
height !== "auto" && !/px$/.test(height) ? `${height}px` : height |
|
||||
|
|
||||
$: card && _bb.attachChildren(card) |
|
||||
</script> |
|
||||
|
|
||||
<div bind:this={card} class={`bbmd-card ${cardClass}`} /> |
|
||||
|
|
||||
<style> |
|
||||
.bbmd-card { |
|
||||
width: 350px; |
|
||||
height: auto; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,12 +0,0 @@ |
|||||
<script> |
|
||||
export let _bb |
|
||||
export let onClick = () => {} |
|
||||
|
|
||||
export let clicked = () => _bb.call(onClick) |
|
||||
|
|
||||
let cardBody |
|
||||
|
|
||||
$: cardBody && _bb.attachChildren(cardBody) |
|
||||
</script> |
|
||||
|
|
||||
<div bind:this={cardBody} class="mdc-card__primary-action" on:click={clicked} /> |
|
||||
@ -1,31 +0,0 @@ |
|||||
<script> |
|
||||
import { onMount } from "svelte" |
|
||||
let cardFooter |
|
||||
export let _bb |
|
||||
export let padding = "5px" |
|
||||
|
|
||||
onMount(() => { |
|
||||
_bb.setContext( |
|
||||
"BBMD:icon-button:context", |
|
||||
"mdc-card__action mdc-card__action--icon" |
|
||||
) |
|
||||
_bb.setContext( |
|
||||
"BBMD:button:context", |
|
||||
"mdc-card__action mdc-card__action--button" |
|
||||
) |
|
||||
}) |
|
||||
|
|
||||
$: cardFooter && _bb.attachChildren(cardFooter) |
|
||||
</script> |
|
||||
|
|
||||
<div |
|
||||
bind:this={cardFooter} |
|
||||
style={`padding: ${padding}`} |
|
||||
class="mdc-card__actions bbmd-card__actions" /> |
|
||||
|
|
||||
<style> |
|
||||
.bbmd-card__actions { |
|
||||
display: flex; |
|
||||
flex-flow: row wrap; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,44 +0,0 @@ |
|||||
<script> |
|
||||
import { H6, Sub2 } from "../Typography" |
|
||||
import Icon from "../Common/Icon.svelte" |
|
||||
export let _bb |
|
||||
export let title = "" |
|
||||
export let subtitle = "" |
|
||||
export let icon = "" |
|
||||
|
|
||||
$: useIcon = !!icon |
|
||||
$: useSubtitle = !!subtitle |
|
||||
</script> |
|
||||
|
|
||||
<div class="card-header"> |
|
||||
{#if useIcon} |
|
||||
<div class="card-header__icon"> |
|
||||
<Icon {icon} /> |
|
||||
</div> |
|
||||
{/if} |
|
||||
<div class="card-header__title"> |
|
||||
<H6 text={title} /> |
|
||||
{#if useSubtitle} |
|
||||
<Sub2 text={subtitle} /> |
|
||||
{/if} |
|
||||
</div> |
|
||||
</div> |
|
||||
|
|
||||
<style> |
|
||||
.card-header { |
|
||||
display: flex; |
|
||||
flex-flow: row nowrap; |
|
||||
padding: 10px; |
|
||||
} |
|
||||
|
|
||||
.card-header__icon { |
|
||||
flex: 0; |
|
||||
padding: 10px; |
|
||||
} |
|
||||
|
|
||||
.card-header__title { |
|
||||
display: flex; |
|
||||
flex-flow: column nowrap; |
|
||||
flex: 1; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,62 +0,0 @@ |
|||||
<script> |
|
||||
import { H6, Sub2 } from "../Typography" |
|
||||
export let _bb |
|
||||
export let displayHorizontal = false //aligns image on row with title and subtitle text |
|
||||
export let url = "" |
|
||||
export let title = "" |
|
||||
export let subtitle = "" |
|
||||
|
|
||||
$: useTitle = !!title |
|
||||
$: useSubTitle = !!subtitle |
|
||||
</script> |
|
||||
|
|
||||
{#if !displayHorizontal} |
|
||||
<div |
|
||||
class="my-card__media mdc-card__media mdc-card__media--16-9" |
|
||||
style={`background-image: url(${url})`}> |
|
||||
<div class="mdc-card__media-content bbmd-card-media__content"> |
|
||||
{#if useTitle} |
|
||||
<H6 text={title} verticalMargin={0} horizontalMargin={10} /> |
|
||||
{#if useSubTitle} |
|
||||
<Sub2 text={subtitle} horizontalMargin={10} /> |
|
||||
{/if} |
|
||||
{/if} |
|
||||
</div> |
|
||||
</div> |
|
||||
{:else} |
|
||||
<div class="bbmd-card--horizontal"> |
|
||||
<div |
|
||||
class="mdc-card__media mdc-card__media mdc-card__media--square |
|
||||
bbmd-card--horizontal-image" |
|
||||
style={`background-image: url(${url})`} /> |
|
||||
<div class="bbmd-card--horizontal-text"> |
|
||||
{#if useTitle} |
|
||||
<H6 text={title} verticalMargin={0} horizontalMargin={10} /> |
|
||||
{#if useSubTitle} |
|
||||
<Sub2 text={subtitle} horizontalMargin={10} /> |
|
||||
{/if} |
|
||||
{/if} |
|
||||
</div> |
|
||||
</div> |
|
||||
{/if} |
|
||||
|
|
||||
<style> |
|
||||
.bbmd-card--horizontal { |
|
||||
display: flex; |
|
||||
flex-flow: row nowrap; |
|
||||
} |
|
||||
|
|
||||
.bbmd-card--horizontal-image { |
|
||||
flex: 0 0 110px; |
|
||||
} |
|
||||
|
|
||||
.bbmd-card--horizontal-text { |
|
||||
flex: 1; |
|
||||
padding: 10px 5px; |
|
||||
} |
|
||||
|
|
||||
.bbmd-card-media__content { |
|
||||
top: 125px; |
|
||||
color: white; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1 +0,0 @@ |
|||||
@import "@material/card/mdc-card.scss" |
|
||||
@ -1,7 +0,0 @@ |
|||||
import "./_styles.scss" |
|
||||
export { default as Card } from "./Card.svelte" |
|
||||
export { default as BasicCard } from "./BasicCard.svelte" |
|
||||
export { default as CardBody } from "./CardBody.svelte" |
|
||||
export { default as CardFooter } from "./CardFooter.svelte" |
|
||||
export { default as CardHeader } from "./CardHeader.svelte" |
|
||||
export { default as CardImage } from "./CardImage.svelte" |
|
||||
@ -1,146 +0,0 @@ |
|||||
<script> |
|
||||
import { onMount, onDestroy } from "svelte" |
|
||||
import Formfield from "../Common/Formfield.svelte" |
|
||||
import { fieldStore } from "../Common/FormfieldStore.js" |
|
||||
import ClassBuilder from "../ClassBuilder.js" |
|
||||
import { MDCCheckbox } from "@material/checkbox" |
|
||||
import { generate } from "shortid" |
|
||||
|
|
||||
export let onChange = item => {} |
|
||||
|
|
||||
export let _bb |
|
||||
|
|
||||
export let id = "" |
|
||||
export let value = null |
|
||||
export let label = "" |
|
||||
export let disabled = false |
|
||||
export let alignEnd = false |
|
||||
export let indeterminate = false |
|
||||
export let checked = false |
|
||||
|
|
||||
let _id |
|
||||
let instance = null |
|
||||
let checkbox = null |
|
||||
let selectedItems |
|
||||
let checkProps |
|
||||
|
|
||||
let context = _bb.getContext("BBMD:input:context") |
|
||||
|
|
||||
onMount(() => { |
|
||||
_id = generate() |
|
||||
|
|
||||
if (!!checkbox) { |
|
||||
instance = new MDCCheckbox(checkbox) |
|
||||
instance.indeterminate = indeterminate |
|
||||
if (context !== "list-item") { |
|
||||
let fieldStore = _bb.getContext("BBMD:field-element") |
|
||||
if (fieldStore) fieldStore.setInput(instance) |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if (context === "checkboxgroup") { |
|
||||
selectedItems = _bb.getContext("BBMD:checkbox:selectedItemsStore") |
|
||||
checkProps = _bb.getContext("BBMD:checkbox:props") |
|
||||
} |
|
||||
}) |
|
||||
|
|
||||
let extras = null |
|
||||
|
|
||||
if (context === "list-item") { |
|
||||
extras = ["mdc-list-item__meta"] |
|
||||
} |
|
||||
|
|
||||
const cb = new ClassBuilder("checkbox") |
|
||||
let modifiers = { disabled } |
|
||||
let props = { modifiers, extras } |
|
||||
|
|
||||
const blockClass = cb.build({ props }) |
|
||||
|
|
||||
function changed(e) { |
|
||||
const val = e.target.checked |
|
||||
checked = val |
|
||||
|
|
||||
handleOnClick() |
|
||||
if (_bb.isBound(_bb.props.checked)) { |
|
||||
_bb.setStateFromBinding(_bb.props.checked, val) |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function handleOnClick() { |
|
||||
let item = { _id, checked, label, value } |
|
||||
if (context === "checkboxgroup") { |
|
||||
let idx = selectedItems.getItemIdx($selectedItems, _id) |
|
||||
if (idx > -1) { |
|
||||
selectedItems.removeItem(_id) |
|
||||
} else { |
|
||||
selectedItems.addItem(item) |
|
||||
} |
|
||||
} |
|
||||
_bb.call(onChange, item) |
|
||||
} |
|
||||
|
|
||||
$: isChecked = |
|
||||
context === "checkboxgroup" |
|
||||
? $selectedItems && $selectedItems.findIndex(i => i._id === _id) > -1 |
|
||||
: checked |
|
||||
|
|
||||
$: isAlignedEnd = |
|
||||
context === "checkboxgroup" && !!checkProps ? checkProps.alignEnd : alignEnd |
|
||||
|
|
||||
$: isDisabled = |
|
||||
context === "checkboxgroup" && !!checkProps ? checkProps.disabled : disabled |
|
||||
</script> |
|
||||
|
|
||||
<!-- TODO: Customizing Colour and Density - What level of customization for these things does Budibase need here? --> |
|
||||
|
|
||||
{#if context !== 'list-item'} |
|
||||
<div class="bbmd-checkbox"> |
|
||||
<Formfield {label} {_bb} {id} alignEnd={isAlignedEnd}> |
|
||||
<div bind:this={checkbox} class={blockClass}> |
|
||||
<input |
|
||||
type="checkbox" |
|
||||
class={cb.elem`native-control`} |
|
||||
{id} |
|
||||
disabled={isDisabled} |
|
||||
checked={isChecked} |
|
||||
on:change={changed} /> |
|
||||
<div class={cb.elem`background`}> |
|
||||
<svg class={cb.elem`checkmark`} viewBox="0 0 24 24"> |
|
||||
<path |
|
||||
class={cb.elem`checkmark-path`} |
|
||||
fill="none" |
|
||||
d="M1.73,12.91 8.1,19.28 22.79,4.59" /> |
|
||||
</svg> |
|
||||
<div class={cb.elem`mixedmark`} /> |
|
||||
</div> |
|
||||
<div class={cb.elem`ripple`} /> |
|
||||
</div> |
|
||||
</Formfield> |
|
||||
</div> |
|
||||
{:else} |
|
||||
<div bind:this={checkbox} class={blockClass}> |
|
||||
<input |
|
||||
type="checkbox" |
|
||||
class={cb.elem`native-control`} |
|
||||
{id} |
|
||||
disabled={isDisabled} |
|
||||
checked={isChecked} |
|
||||
on:change={changed} /> |
|
||||
<div class={cb.elem`background`}> |
|
||||
<svg class={cb.elem`checkmark`} viewBox="0 0 24 24"> |
|
||||
<path |
|
||||
class={cb.elem`checkmark-path`} |
|
||||
fill="none" |
|
||||
d="M1.73,12.91 8.1,19.28 22.79,4.59" /> |
|
||||
</svg> |
|
||||
<div class={cb.elem`mixedmark`} /> |
|
||||
</div> |
|
||||
<div class={cb.elem`ripple`} /> |
|
||||
</div> |
|
||||
{/if} |
|
||||
|
|
||||
<style> |
|
||||
.bbmd-checkbox { |
|
||||
width: fit-content; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,69 +0,0 @@ |
|||||
<script> |
|
||||
import { onMount } from "svelte" |
|
||||
import Checkbox from "./Checkbox.svelte" |
|
||||
import Label from "../Common/Label.svelte" |
|
||||
import createItemsStore from "../Common/ItemStore.js" |
|
||||
|
|
||||
let selectedItemsStore |
|
||||
let checkItems |
|
||||
|
|
||||
export let _bb |
|
||||
export let label = "" |
|
||||
export let orientation = "row" |
|
||||
export let onChange = selectedItems => {} |
|
||||
|
|
||||
export let disabled = false |
|
||||
export let alignEnd = false |
|
||||
export let value = [] |
|
||||
|
|
||||
onMount(() => { |
|
||||
_bb.setContext("BBMD:input:context", "checkboxgroup") |
|
||||
selectedItemsStore = createItemsStore(() => { |
|
||||
value = $selectedItemsStore |
|
||||
if (_bb.isBound(_bb.props.value)) { |
|
||||
_bb.setStateFromBinding(_bb.props.value, value) |
|
||||
} |
|
||||
_bb.call(onChange, value) |
|
||||
}, value) |
|
||||
_bb.setContext("BBMD:checkbox:selectedItemsStore", selectedItemsStore) |
|
||||
_bb.setContext("BBMD:checkbox:props", { alignEnd, disabled }) |
|
||||
}) |
|
||||
|
|
||||
$: checkItems && _bb.attachChildren(checkItems) |
|
||||
</script> |
|
||||
|
|
||||
<div class="checkbox-group"> |
|
||||
<div class="checkbox-group__label"> |
|
||||
<Label text={label} bold /> |
|
||||
</div> |
|
||||
<div bind:this={checkItems} class={`checkbox-group__boxes ${orientation}`} /> |
|
||||
</div> |
|
||||
|
|
||||
<style> |
|
||||
.checkbox-group { |
|
||||
display: flex; |
|
||||
flex-direction: column; |
|
||||
width: fit-content; |
|
||||
} |
|
||||
|
|
||||
.checkbox-group__boxes.row > div:not(:first-child) { |
|
||||
padding-left: 10px; |
|
||||
} |
|
||||
|
|
||||
.checkbox-group > div { |
|
||||
text-align: left; |
|
||||
flex: 1; |
|
||||
} |
|
||||
|
|
||||
.row { |
|
||||
display: flex; |
|
||||
flex-flow: row wrap; |
|
||||
align-items: flex-start; |
|
||||
} |
|
||||
|
|
||||
.column { |
|
||||
display: flex; |
|
||||
flex-flow: column wrap; |
|
||||
align-items: flex-start; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,2 +0,0 @@ |
|||||
@import "@material/form-field/mdc-form-field"; |
|
||||
@import "@material/checkbox/mdc-checkbox.scss"; |
|
||||
@ -1,3 +0,0 @@ |
|||||
import "./_style.scss" |
|
||||
export { default as Checkbox } from "./Checkbox.svelte" |
|
||||
export { default as Checkboxgroup } from "./CheckboxGroup.svelte" |
|
||||
@ -1,74 +0,0 @@ |
|||||
export default class ClassBuilder { |
|
||||
constructor(block, defaultIgnoreList) { |
|
||||
this.block = `mdc-${block}` |
|
||||
this.defaultIgnoreList = defaultIgnoreList //will be ignored when building custom classes
|
|
||||
} |
|
||||
|
|
||||
/* |
|
||||
handles both blocks and elementss (BEM MD Notation) |
|
||||
params = {elementName: string, props: {modifiers{}, customs:{}, extras: []}} |
|
||||
All are optional |
|
||||
*/ |
|
||||
build(params) { |
|
||||
if (!params) return this.block //return block if nothing passed
|
|
||||
const { props, elementName } = params |
|
||||
let base = elementName ? `${this.block}__${elementName}` : this.block |
|
||||
if (!props) return base |
|
||||
return this._handleProps(base, props) |
|
||||
} |
|
||||
|
|
||||
//Easily grab a simple element class
|
|
||||
elem(elementName) { |
|
||||
return this.build({ elementName }) |
|
||||
} |
|
||||
|
|
||||
//use if a different base is needed than whats defined by this.block
|
|
||||
debase(base, elementProps) { |
|
||||
if (!elementProps) return base |
|
||||
return this._handleProps(base, elementProps) |
|
||||
} |
|
||||
|
|
||||
//proxies bindProps and checks for which elementProps exist before binding
|
|
||||
_handleProps(base, elementProps) { |
|
||||
let cls = base |
|
||||
const { modifiers, customs, extras } = elementProps |
|
||||
if (modifiers) cls += this._bindProps(modifiers, base) |
|
||||
if (customs) cls += this._bindProps(customs, base, true) |
|
||||
if (extras) cls += ` ${extras.join(" ")}` |
|
||||
return cls.trim() |
|
||||
} |
|
||||
|
|
||||
/* |
|
||||
Handles both modifiers and customs. Use property, value or both depending |
|
||||
on whether it is passsed props for custom or modifiers |
|
||||
if custom uses the following convention for scss mixins: |
|
||||
bbmd-{this.block}--{property}-{value} |
|
||||
bbmd-mdc-button--size-large |
|
||||
*/ |
|
||||
_bindProps(elementProps, base, isCustom = false) { |
|
||||
return Object.entries(elementProps) |
|
||||
.map(([property, value]) => { |
|
||||
//disregard falsy and values set by defaultIgnoreList constructor param
|
|
||||
if ( |
|
||||
!!value && |
|
||||
(!this.defaultIgnoreList || !this.defaultIgnoreList.includes(value)) |
|
||||
) { |
|
||||
let classBase = isCustom ? `bbmd-${base}` : `${base}` |
|
||||
let valueType = typeof value |
|
||||
|
|
||||
if (valueType == "string" || valueType == "number") { |
|
||||
return isCustom |
|
||||
? ` ${classBase}--${this._convertCamel(property)}-${value}` |
|
||||
: ` ${classBase}--${value}` |
|
||||
} else if (valueType == "boolean") { |
|
||||
return ` ${classBase}--${this._convertCamel(property)}` |
|
||||
} |
|
||||
} |
|
||||
}) |
|
||||
.join("") |
|
||||
} |
|
||||
|
|
||||
_convertCamel(str) { |
|
||||
return str.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`) |
|
||||
} |
|
||||
} |
|
||||
@ -1,7 +0,0 @@ |
|||||
<script> |
|
||||
import "@material/floating-label/mdc-floating-label.scss" |
|
||||
export let forInput = "" |
|
||||
export let text = "" |
|
||||
</script> |
|
||||
|
|
||||
<label for={forInput} class="mdc-floating-label">{text}</label> |
|
||||
@ -1,42 +0,0 @@ |
|||||
<script> |
|
||||
import "@material/form-field/mdc-form-field.scss" |
|
||||
import ClassBuilder from "../ClassBuilder.js" |
|
||||
import { fieldStore } from "./FormfieldStore.js" |
|
||||
import { MDCFormField } from "@material/form-field" |
|
||||
import { onMount, onDestroy } from "svelte" |
|
||||
|
|
||||
const cb = new ClassBuilder("form-field") |
|
||||
|
|
||||
let store |
|
||||
const unsubscribe = fieldStore.subscribe(s => (store = s)) |
|
||||
|
|
||||
export let _bb |
|
||||
export let id = "" |
|
||||
export let label = "" |
|
||||
export let alignEnd = false |
|
||||
|
|
||||
let formField = null |
|
||||
|
|
||||
$: modifiers = { alignEnd } |
|
||||
$: props = { modifiers, extras: ["bbmd-form-field"] } |
|
||||
|
|
||||
$: blockClasses = cb.build({ props }) |
|
||||
|
|
||||
onMount(() => { |
|
||||
if (!!formField) fieldStore.set(new MDCFormField(formField)) |
|
||||
_bb.setContext("BBMD:field-element", fieldStore) |
|
||||
}) |
|
||||
|
|
||||
onDestroy(unsubscribe) |
|
||||
</script> |
|
||||
|
|
||||
<div bind:this={formField} class={blockClasses}> |
|
||||
<slot /> |
|
||||
<label for={id}>{label}</label> |
|
||||
</div> |
|
||||
|
|
||||
<style> |
|
||||
.bbmd-form-field { |
|
||||
width: fit-content; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,19 +0,0 @@ |
|||||
import { writable } from "svelte/store" |
|
||||
|
|
||||
function store() { |
|
||||
const { set, update, subscribe } = writable({}) |
|
||||
|
|
||||
function setInput(inp) { |
|
||||
update(n => { |
|
||||
n.input = inp |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
return { |
|
||||
subscribe, |
|
||||
set, |
|
||||
setInput, |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
export const fieldStore = store() |
|
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue