@ -1,56 +1,47 @@ |
|||||
<script> |
<script> |
||||
|
import BackendNav from "./nav/BackendNav.svelte" |
||||
|
import Database from "./database/DatabaseRoot.svelte" |
||||
|
import UserInterface from "./userInterface/UserInterfaceRoot.svelte" |
||||
|
import ActionsAndTriggers from "./actionsAndTriggers/ActionsAndTriggersRoot.svelte" |
||||
|
import AccessLevels from "./accessLevels/AccessLevelsRoot.svelte" |
||||
|
import ComingSoon from "./common/ComingSoon.svelte" |
||||
|
|
||||
import BackendNav from "./nav/BackendNav.svelte"; |
import { store } from "./builderStore" |
||||
import Database from "./database/DatabaseRoot.svelte" ; |
|
||||
import UserInterface from "./userInterface/UserInterfaceRoot.svelte" ; |
|
||||
import ActionsAndTriggers from "./actionsAndTriggers/ActionsAndTriggersRoot.svelte" ; |
|
||||
import AccessLevels from "./accessLevels/AccessLevelsRoot.svelte" ; |
|
||||
import ComingSoon from "./common/ComingSoon.svelte"; |
|
||||
|
|
||||
import {store} from "./builderStore"; |
|
||||
|
|
||||
export let navWidth = "50px"; |
|
||||
|
|
||||
|
|
||||
|
export let navWidth = "50px" |
||||
</script> |
</script> |
||||
|
|
||||
<div class="root"> |
<div class="root"> |
||||
<div class="nav"> |
<div class="nav"> |
||||
<BackendNav /> |
<BackendNav /> |
||||
</div> |
</div> |
||||
<div class="content" |
<div class="content" style="width: calc(100% - {navWidth}); left: {navWidth}"> |
||||
style="width: calc(100% - {navWidth}); left: {navWidth}"> |
{#if $store.activeNav === 'database'} |
||||
{#if $store.activeNav === "database"} |
<Database /> |
||||
<Database /> |
{:else if $store.activeNav === 'actions'} |
||||
{:else if $store.activeNav === "actions"} |
<ActionsAndTriggers /> |
||||
<ActionsAndTriggers /> |
{:else if $store.activeNav === 'access levels'} |
||||
{:else if $store.activeNav === "access levels"} |
<AccessLevels /> |
||||
<AccessLevels /> |
|
||||
{/if} |
{/if} |
||||
</div> |
</div> |
||||
</div> |
</div> |
||||
|
|
||||
|
|
||||
|
|
||||
<style> |
<style> |
||||
|
.root { |
||||
.root { |
height: 100%; |
||||
height: 100%; |
display: flex; |
||||
display: flex; |
} |
||||
} |
|
||||
|
.content { |
||||
|
flex: 1 1 auto; |
||||
.content { |
height: 100%; |
||||
flex: 1 1 auto; |
background-color: var(--white); |
||||
height: 100%; |
margin: 0; |
||||
background-color: var(--white); |
} |
||||
margin:0; |
|
||||
} |
.nav { |
||||
|
flex: 0 1 auto; |
||||
.nav { |
width: 300px; |
||||
flex: 0 1 auto; |
height: 100%; |
||||
width: 300px; |
} |
||||
height: 100%; |
</style> |
||||
} |
|
||||
|
|
||||
</style> |
|
||||
|
|||||
@ -1,56 +1,55 @@ |
|||||
<script> |
<script> |
||||
|
import Button from "./common/Button.svelte" |
||||
|
import { store } from "./builderStore" |
||||
|
|
||||
import Button from "./common/Button.svelte" |
let errors = [] |
||||
import { store } from "./builderStore"; |
|
||||
|
|
||||
let errors = []; |
|
||||
|
|
||||
</script> |
</script> |
||||
|
|
||||
<div class="root"> |
<div class="root"> |
||||
<div class="inner"> |
<div class="inner"> |
||||
<img src="/_builder/assets/budibase-logo.png" class="logo" alt="budibase logo"/> |
<img |
||||
<div> |
src="/_builder/assets/budibase-logo.png" |
||||
|
class="logo" |
||||
<div> |
alt="budibase logo" /> |
||||
<h4 style="margin-bottom: 20px">Choose an Application</h4> |
<div> |
||||
{#each $store.apps as app} |
|
||||
<a href={`#/${app}`} class="app-link">{app}</a> |
<div> |
||||
{/each} |
<h4 style="margin-bottom: 20px">Choose an Application</h4> |
||||
</div> |
{#each $store.apps as app} |
||||
</div> |
<a href={`#/${app}`} class="app-link">{app}</a> |
||||
|
{/each} |
||||
|
</div> |
||||
</div> |
</div> |
||||
|
</div> |
||||
</div> |
</div> |
||||
|
|
||||
<style> |
<style> |
||||
|
.root { |
||||
.root { |
|
||||
position: fixed; |
position: fixed; |
||||
margin: 0 auto; |
margin: 0 auto; |
||||
text-align: center; |
text-align: center; |
||||
top: 20%; |
top: 20%; |
||||
/*color: #333333; |
/*color: #333333; |
||||
background-color: #fdfdfd;*/ |
background-color: #fdfdfd;*/ |
||||
width:100%; |
width: 100%; |
||||
} |
} |
||||
|
|
||||
.inner { |
.inner { |
||||
display:inline-block; |
display: inline-block; |
||||
margin: auto; |
margin: auto; |
||||
} |
} |
||||
|
|
||||
.logo { |
.logo { |
||||
width: 300px; |
width: 300px; |
||||
margin-bottom: 40px; |
margin-bottom: 40px; |
||||
} |
} |
||||
|
|
||||
.root :global(.option) { |
.root :global(.option) { |
||||
width:250px; |
width: 250px; |
||||
} |
} |
||||
|
|
||||
.app-link { |
.app-link { |
||||
margin-top: 10px; |
margin-top: 10px; |
||||
display: block; |
display: block; |
||||
} |
} |
||||
|
</style> |
||||
</style> |
|
||||
|
|||||
@ -1,27 +1,26 @@ |
|||||
<script> |
<script> |
||||
|
import IconButton from "./common/IconButton.svelte" |
||||
import IconButton from "./common/IconButton.svelte"; |
import { store } from "./builderStore" |
||||
import { store } from "./builderStore"; |
import UserInterfaceRoot from "./userInterface/UserInterfaceRoot.svelte" |
||||
import UserInterfaceRoot from "./userInterface/UserInterfaceRoot.svelte"; |
import { fade } from "svelte/transition" |
||||
import { fade } from "svelte/transition"; |
|
||||
|
|
||||
</script> |
</script> |
||||
|
|
||||
<div class="root"> |
<div class="root"> |
||||
<div class="content uk-container"> |
<div class="content uk-container"> |
||||
|
|
||||
<h1>Settings</h1> |
<h1>Settings</h1> |
||||
|
|
||||
<label> |
<label> |
||||
<input type="checkbox" |
<input |
||||
class="uk-checkbox" |
type="checkbox" |
||||
bind:checked={$store.useAnalytics}> |
class="uk-checkbox" |
||||
Send analytics |
bind:checked={$store.useAnalytics} /> |
||||
</label> |
Send analytics |
||||
|
</label> |
||||
|
|
||||
</div> |
</div> |
||||
</div> |
</div> |
||||
|
|
||||
<style> |
<style> |
||||
|
|
||||
</style> |
</style> |
||||
|
|||||
@ -1,99 +1,91 @@ |
|||||
<script> |
<script> |
||||
|
import { cloneDeep, map, some, filter } from "lodash/fp" |
||||
|
import Textbox from "../common/Textbox.svelte" |
||||
|
import Checkbox from "../common/Checkbox.svelte" |
||||
|
import ButtonGroup from "../common/ButtonGroup.svelte" |
||||
|
import Button from "../common/Button.svelte" |
||||
|
import { validateAccessLevels } from "../common/core" |
||||
|
import ErrorsBox from "../common/ErrorsBox.svelte" |
||||
|
|
||||
import {cloneDeep, map, some, filter} from "lodash/fp"; |
export let level |
||||
import Textbox from "../common/Textbox.svelte"; |
export let allPermissions |
||||
import Checkbox from "../common/Checkbox.svelte"; |
export let onFinished |
||||
import ButtonGroup from "../common/ButtonGroup.svelte"; |
export let isNew |
||||
import Button from "../common/Button.svelte"; |
export let allLevels |
||||
import {validateAccessLevels} from "../common/core"; |
export let hierarchy |
||||
import ErrorsBox from "../common/ErrorsBox.svelte"; |
export let actions |
||||
|
|
||||
export let level; |
let errors = [] |
||||
export let allPermissions; |
let clonedLevel = cloneDeep(level) |
||||
export let onFinished; |
|
||||
export let isNew; |
const matchPermissions = (p1, p2) => |
||||
export let allLevels; |
p1.type === p2.type && |
||||
export let hierarchy; |
((!p2.nodeKey && !p1.nodeKey) || p2.nodeKey === p1.nodeKey) |
||||
export let actions; |
|
||||
|
const hasPermission = hasPerm => |
||||
let errors = []; |
some(p => matchPermissions(p, hasPerm))(clonedLevel.permissions) |
||||
let clonedLevel = cloneDeep(level); |
|
||||
|
$: permissionMatrix = map(p => ({ |
||||
const matchPermissions = (p1, p2) => |
permission: p, |
||||
p1.type === p2.type |
hasPermission: hasPermission(p), |
||||
&& |
}))(allPermissions) |
||||
((!p2.nodeKey && !p1.nodeKey) |
|
||||
|| p2.nodeKey === p1.nodeKey); |
const getPermissionName = perm => |
||||
|
perm.nodeKey ? `${perm.type} - ${perm.nodeKey}` : perm.type |
||||
const hasPermission = hasPerm => |
|
||||
some(p => matchPermissions(p, hasPerm)) |
const save = () => { |
||||
(clonedLevel.permissions); |
const newLevels = isNew |
||||
|
? [...allLevels, clonedLevel] |
||||
$: permissionMatrix = |
: [...filter(l => l.name !== level.name)(allLevels), clonedLevel] |
||||
map(p => ({permission:p, hasPermission: hasPermission(p)})) |
|
||||
(allPermissions) |
errors = validateAccessLevels(hierarchy, actions, newLevels) |
||||
|
|
||||
const getPermissionName = perm => |
if (errors.length > 0) return |
||||
perm.nodeKey |
|
||||
? `${perm.type} - ${perm.nodeKey}` |
onFinished(clonedLevel) |
||||
: perm.type; |
} |
||||
|
|
||||
const save = () => { |
const permissionChanged = perm => ev => { |
||||
|
const hasPermission = ev.target.checked |
||||
const newLevels = |
|
||||
isNew |
if (hasPermission) { |
||||
? [...allLevels, clonedLevel] |
clonedLevel.permissions.push(perm) |
||||
: [...filter(l => l.name !== level.name)(allLevels), clonedLevel]; |
|
||||
|
|
||||
errors = validateAccessLevels( |
|
||||
hierarchy, |
|
||||
actions, |
|
||||
newLevels |
|
||||
); |
|
||||
|
|
||||
if(errors.length > 0) return; |
|
||||
|
|
||||
onFinished(clonedLevel); |
|
||||
} |
|
||||
|
|
||||
const permissionChanged = perm => ev => { |
|
||||
const hasPermission = ev.target.checked; |
|
||||
|
|
||||
if(hasPermission) { |
|
||||
clonedLevel.permissions.push(perm); |
|
||||
} else { |
} else { |
||||
clonedLevel.permissions = filter(p => !matchPermissions(p, perm))(clonedLevel.permissions); |
clonedLevel.permissions = filter(p => !matchPermissions(p, perm))( |
||||
|
clonedLevel.permissions |
||||
|
) |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
</script> |
</script> |
||||
|
|
||||
<div> |
<div> |
||||
|
|
||||
<ErrorsBox {errors} /> |
<ErrorsBox {errors} /> |
||||
|
|
||||
<form class="uk-form-horizontal"> |
|
||||
|
|
||||
<Textbox label="Name" bind:text={clonedLevel.name} /> |
<form class="uk-form-horizontal"> |
||||
|
|
||||
{#each permissionMatrix as permission} |
<Textbox label="Name" bind:text={clonedLevel.name} /> |
||||
<div> |
|
||||
<Checkbox label={getPermissionName(permission.permission)} |
|
||||
checked={permission.hasPermission} |
|
||||
on:change={permissionChanged(permission.permission)} /> |
|
||||
</div> |
|
||||
{/each} |
|
||||
|
|
||||
</form> |
{#each permissionMatrix as permission} |
||||
|
<div> |
||||
|
<Checkbox |
||||
|
label={getPermissionName(permission.permission)} |
||||
|
checked={permission.hasPermission} |
||||
|
on:change={permissionChanged(permission.permission)} /> |
||||
|
</div> |
||||
|
{/each} |
||||
|
|
||||
<ButtonGroup style="margin-top: 10px"> |
</form> |
||||
<Button color="primary" grouped on:click={save}>Save</Button> |
|
||||
<Button color="secondary" grouped on:click={() => onFinished()}>Cancel</Button> |
|
||||
</ButtonGroup> |
|
||||
|
|
||||
|
<ButtonGroup style="margin-top: 10px"> |
||||
|
<Button color="primary" grouped on:click={save}>Save</Button> |
||||
|
<Button color="secondary" grouped on:click={() => onFinished()}> |
||||
|
Cancel |
||||
|
</Button> |
||||
|
</ButtonGroup> |
||||
|
|
||||
</div> |
</div> |
||||
|
|
||||
<style> |
<style> |
||||
|
|
||||
</style> |
</style> |
||||
|
|||||
@ -1,119 +1,115 @@ |
|||||
<script> |
<script> |
||||
|
import ButtonGroup from "../common/ButtonGroup.svelte" |
||||
import ButtonGroup from "../common/ButtonGroup.svelte"; |
import Button from "../common/Button.svelte" |
||||
import Button from "../common/Button.svelte"; |
import { store } from "../builderStore" |
||||
import {store} from "../builderStore"; |
import { generateFullPermissions, getNewAccessLevel } from "../common/core" |
||||
import {generateFullPermissions, getNewAccessLevel} from "../common/core"; |
import getIcon from "../common/icon" |
||||
import getIcon from "../common/icon"; |
import AccessLevelView from "./AccessLevelView.svelte" |
||||
import AccessLevelView from "./AccessLevelView.svelte"; |
import Modal from "../common/Modal.svelte" |
||||
import Modal from "../common/Modal.svelte"; |
|
||||
|
let editingLevel = null |
||||
let editingLevel = null; |
let editingLevelIsNew = false |
||||
let editingLevelIsNew = false; |
$: isEditing = editingLevel !== null |
||||
$: isEditing = (editingLevel !== null); |
|
||||
|
let allPermissions = [] |
||||
let allPermissions = []; |
store.subscribe(db => { |
||||
store.subscribe(db => { |
allPermissions = generateFullPermissions(db.hierarchy, db.actions) |
||||
allPermissions = generateFullPermissions(db.hierarchy, db.actions); |
}) |
||||
}) |
|
||||
|
let onLevelEdit = level => { |
||||
let onLevelEdit = (level) => { |
editingLevel = level |
||||
editingLevel = level; |
editingLevelIsNew = false |
||||
editingLevelIsNew = false; |
} |
||||
}; |
|
||||
|
let onLevelCancel = () => { |
||||
let onLevelCancel = () => { |
editingAction = null |
||||
editingAction = null; |
} |
||||
}; |
|
||||
|
let onLevelDelete = level => { |
||||
let onLevelDelete = (level) => { |
store.deleteLevel(level) |
||||
store.deleteLevel(level); |
} |
||||
}; |
|
||||
|
let createNewLevel = () => { |
||||
|
editingLevelIsNew = true |
||||
let createNewLevel = () => { |
editingLevel = getNewAccessLevel() |
||||
editingLevelIsNew = true; |
} |
||||
editingLevel = getNewAccessLevel(); |
|
||||
} |
let onEditingFinished = level => { |
||||
|
if (level) { |
||||
let onEditingFinished = (level) => { |
store.saveLevel(level, editingLevelIsNew, editingLevel) |
||||
if(level) { |
|
||||
store.saveLevel(level, editingLevelIsNew, editingLevel); |
|
||||
} |
} |
||||
editingLevel = null; |
editingLevel = null |
||||
} |
} |
||||
|
|
||||
const getPermissionsString = perms => { |
|
||||
return `${perms.length} / ${allPermissions.length}`; |
|
||||
} |
|
||||
|
|
||||
|
const getPermissionsString = perms => { |
||||
|
return `${perms.length} / ${allPermissions.length}` |
||||
|
} |
||||
</script> |
</script> |
||||
|
|
||||
<div class="root"> |
<div class="root"> |
||||
|
|
||||
<ButtonGroup> |
<ButtonGroup> |
||||
<Button grouped color="secondary" on:click={createNewLevel}>Create New Access Level</Button> |
<Button grouped color="secondary" on:click={createNewLevel}> |
||||
</ButtonGroup> |
Create New Access Level |
||||
|
</Button> |
||||
|
</ButtonGroup> |
||||
|
|
||||
{#if $store.accessLevels} |
{#if $store.accessLevels} |
||||
<table class="fields-table uk-table uk-table-small"> |
<table class="fields-table uk-table uk-table-small"> |
||||
<thead> |
<thead> |
||||
<tr> |
<tr> |
||||
<th>Name</th> |
<th>Name</th> |
||||
<th>Permissions</th> |
<th>Permissions</th> |
||||
<th></th> |
<th /> |
||||
</tr> |
</tr> |
||||
</thead> |
</thead> |
||||
<tbody> |
<tbody> |
||||
{#each $store.accessLevels.levels as level} |
{#each $store.accessLevels.levels as level} |
||||
<tr> |
<tr> |
||||
<td >{level.name}</td> |
<td>{level.name}</td> |
||||
<td >{getPermissionsString(level.permissions)}</td> |
<td>{getPermissionsString(level.permissions)}</td> |
||||
<td class="edit-button"> |
<td class="edit-button"> |
||||
<span on:click={() => onLevelEdit(level)}>{@html getIcon("edit")}</span> |
<span on:click={() => onLevelEdit(level)}> |
||||
<span on:click={() => onLevelDelete(level)}>{@html getIcon("trash")}</span> |
{@html getIcon('edit')} |
||||
|
</span> |
||||
|
<span on:click={() => onLevelDelete(level)}> |
||||
|
{@html getIcon('trash')} |
||||
|
</span> |
||||
</td> |
</td> |
||||
</tr> |
</tr> |
||||
{/each} |
{/each} |
||||
</tbody> |
</tbody> |
||||
</table> |
</table> |
||||
{:else} |
{:else}(no actions added){/if} |
||||
(no actions added) |
|
||||
{/if} |
|
||||
|
|
||||
|
|
||||
<Modal bind:isOpen={isEditing}> |
<Modal bind:isOpen={isEditing}> |
||||
{#if isEditing} |
{#if isEditing} |
||||
<AccessLevelView level={editingLevel} |
<AccessLevelView |
||||
allPermissions={allPermissions} |
level={editingLevel} |
||||
onFinished={onEditingFinished} |
{allPermissions} |
||||
isNew={editingLevelIsNew} |
onFinished={onEditingFinished} |
||||
allLevels={$store.accessLevels.levels} |
isNew={editingLevelIsNew} |
||||
hierarchy={$store.hierarchy} |
allLevels={$store.accessLevels.levels} |
||||
actions={$store.actions} /> |
hierarchy={$store.hierarchy} |
||||
{/if} |
actions={$store.actions} /> |
||||
</Modal> |
{/if} |
||||
|
</Modal> |
||||
|
|
||||
</div> |
</div> |
||||
|
|
||||
<style> |
<style> |
||||
|
.root { |
||||
.root { |
|
||||
height: 100%; |
height: 100%; |
||||
position: relative; |
position: relative; |
||||
padding: 1.5rem; |
padding: 1.5rem; |
||||
|
} |
||||
|
|
||||
} |
.actions-header { |
||||
|
|
||||
.actions-header { |
|
||||
flex: 0 1 auto; |
flex: 0 1 auto; |
||||
} |
} |
||||
|
|
||||
.node-view { |
.node-view { |
||||
overflow-y: auto; |
overflow-y: auto; |
||||
flex: 1 1 auto; |
flex: 1 1 auto; |
||||
} |
} |
||||
|
</style> |
||||
|
|
||||
</style> |
|
||||
|
|||||
@ -1,123 +1,134 @@ |
|||||
<script> |
<script> |
||||
|
import Textbox from "../common/Textbox.svelte" |
||||
import Textbox from "../common/Textbox.svelte"; |
import Button from "../common/Button.svelte" |
||||
import Button from "../common/Button.svelte"; |
import ButtonGroup from "../common/ButtonGroup.svelte" |
||||
import ButtonGroup from "../common/ButtonGroup.svelte"; |
import { cloneDeep, filter, keys, map, isUndefined } from "lodash/fp" |
||||
import {cloneDeep, filter, keys, |
import ErrorsBox from "../common/ErrorsBox.svelte" |
||||
map, isUndefined} from "lodash/fp"; |
import { validateActions, pipe } from "../common/core" |
||||
import ErrorsBox from "../common/ErrorsBox.svelte"; |
import getIcon from "../common/icon" |
||||
import {validateActions, pipe} from "../common/core"; |
|
||||
import getIcon from "../common/icon"; |
export let action |
||||
|
export let onFinished = action => {} |
||||
export let action; |
export let allActions |
||||
export let onFinished = (action) => {}; |
export let isNew = true |
||||
export let allActions; |
|
||||
export let isNew = true; |
let optKey = "" |
||||
|
let optValue = "" |
||||
let optKey = ""; |
|
||||
let optValue = ""; |
let clonedAction = cloneDeep(action) |
||||
|
let initialOptions = pipe(action.initialOptions, [ |
||||
let clonedAction = cloneDeep(action); |
|
||||
let initialOptions = pipe(action.initialOptions, [ |
|
||||
keys, |
keys, |
||||
map(k => ({key:k, value:action.initialOptions[k]})) |
map(k => ({ key: k, value: action.initialOptions[k] })), |
||||
]); |
]) |
||||
let errors = []; |
let errors = [] |
||||
|
|
||||
const addNewOption = () => { |
const addNewOption = () => { |
||||
|
if ( |
||||
if(optKey && optValue && isUndefined(clonedAction.initialOptions[optKey])) { |
optKey && |
||||
clonedAction.initialOptions[optKey] = optValue; |
optValue && |
||||
initialOptions = [...initialOptions, { |
isUndefined(clonedAction.initialOptions[optKey]) |
||||
key:optKey, value: optValue |
) { |
||||
}]; |
clonedAction.initialOptions[optKey] = optValue |
||||
optKey = ""; |
initialOptions = [ |
||||
optValue = ""; |
...initialOptions, |
||||
} |
{ |
||||
} |
key: optKey, |
||||
|
value: optValue, |
||||
const removeOption = (opt) => { |
}, |
||||
if(opt) { |
] |
||||
delete clonedAction.initialOptions[opt.key] |
optKey = "" |
||||
initialOptions = pipe(initialOptions, [ |
optValue = "" |
||||
filter(o => o.key !== opt.key) |
|
||||
]); |
|
||||
} |
} |
||||
} |
} |
||||
|
|
||||
const save = () => { |
const removeOption = opt => { |
||||
|
if (opt) { |
||||
|
delete clonedAction.initialOptions[opt.key] |
||||
|
initialOptions = pipe(initialOptions, [filter(o => o.key !== opt.key)]) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const save = () => { |
||||
const newActionsList = [ |
const newActionsList = [ |
||||
...pipe(allActions ,[filter(a => a !== action)]), |
...pipe(allActions, [filter(a => a !== action)]), |
||||
clonedAction] |
clonedAction, |
||||
|
] |
||||
|
|
||||
errors = pipe(newActionsList ,[ |
errors = pipe(newActionsList, [validateActions, map(e => e.error)]) |
||||
validateActions, |
|
||||
map(e => e.error) |
|
||||
]); |
|
||||
|
|
||||
if(errors.length === 0) |
if (errors.length === 0) onFinished(clonedAction) |
||||
onFinished(clonedAction); |
} |
||||
} |
|
||||
|
|
||||
const cancel = () => { |
|
||||
onFinished(); |
|
||||
} |
|
||||
|
|
||||
|
const cancel = () => { |
||||
|
onFinished() |
||||
|
} |
||||
</script> |
</script> |
||||
|
|
||||
<div class="root"> |
<div class="root"> |
||||
|
|
||||
<ErrorsBox {errors} /> |
<ErrorsBox {errors} /> |
||||
|
|
||||
<form class="uk-form-horizontal"> |
<form class="uk-form-horizontal"> |
||||
|
|
||||
<Textbox label="Name" bind:text={clonedAction.name} /> |
<Textbox label="Name" bind:text={clonedAction.name} /> |
||||
<Textbox label="Behaviour Source" bind:text={clonedAction.behaviourSource} /> |
<Textbox |
||||
<Textbox label="Behaviour" bind:text={clonedAction.behaviourName} /> |
label="Behaviour Source" |
||||
|
bind:text={clonedAction.behaviourSource} /> |
||||
</form> |
<Textbox label="Behaviour" bind:text={clonedAction.behaviourName} /> |
||||
|
|
||||
<div class=" uk-form-stacked" style="margin-bottom: 20px"> |
</form> |
||||
<label class="uk-form-label">Default Options</label> |
|
||||
<div class="uk-grid-small" uk-grid> |
<div class=" uk-form-stacked" style="margin-bottom: 20px"> |
||||
<input class="uk-input uk-width-1-4 uk-margin-right" placeholder="key" bind:value={optKey} > |
<label class="uk-form-label">Default Options</label> |
||||
<input class="uk-input uk-width-1-4 uk-margin-right" placeholder="value" bind:value={optValue} > |
<div class="uk-grid-small" uk-grid> |
||||
<Button color="primary-outline uk-width-1-4" on:click={addNewOption}>Add</Button> |
<input |
||||
</div> |
class="uk-input uk-width-1-4 uk-margin-right" |
||||
<div style="margin-top: 10px"> |
placeholder="key" |
||||
{#each initialOptions as option} |
bind:value={optKey} /> |
||||
<span class="option-container">{option.key} : {option.value} <span style="font-size:10pt; cursor: pointer" on:click={() => removeOption(option)}>{@html getIcon("trash-2")}</span></span> |
<input |
||||
{/each} |
class="uk-input uk-width-1-4 uk-margin-right" |
||||
</div> |
placeholder="value" |
||||
|
bind:value={optValue} /> |
||||
|
<Button color="primary-outline uk-width-1-4" on:click={addNewOption}> |
||||
|
Add |
||||
|
</Button> |
||||
|
</div> |
||||
|
<div style="margin-top: 10px"> |
||||
|
{#each initialOptions as option} |
||||
|
<span class="option-container"> |
||||
|
{option.key} : {option.value} |
||||
|
<span |
||||
|
style="font-size:10pt; cursor: pointer" |
||||
|
on:click={() => removeOption(option)}> |
||||
|
{@html getIcon('trash-2')} |
||||
|
</span> |
||||
|
</span> |
||||
|
{/each} |
||||
</div> |
</div> |
||||
|
</div> |
||||
|
|
||||
<ButtonGroup> |
<ButtonGroup> |
||||
<Button color="secondary" grouped on:click={save}>Save</Button> |
<Button color="secondary" grouped on:click={save}>Save</Button> |
||||
<Button color="tertiary" grouped on:click={cancel}>Cancel</Button> |
<Button color="tertiary" grouped on:click={cancel}>Cancel</Button> |
||||
</ButtonGroup> |
</ButtonGroup> |
||||
|
|
||||
|
|
||||
</div> |
</div> |
||||
|
|
||||
|
|
||||
<style> |
<style> |
||||
|
.root { |
||||
.root { |
|
||||
padding: 2rem; |
padding: 2rem; |
||||
border-radius: 2rem; |
border-radius: 2rem; |
||||
} |
} |
||||
|
|
||||
.uk-grid-small { |
.uk-grid-small { |
||||
padding: 1rem; |
padding: 1rem; |
||||
} |
} |
||||
|
|
||||
.option-container { |
.option-container { |
||||
border-style: dotted; |
border-style: dotted; |
||||
border-width: 1px; |
border-width: 1px; |
||||
border-color: var(--primary75); |
border-color: var(--primary75); |
||||
padding: 3px; |
padding: 3px; |
||||
margin-right: 5px; |
margin-right: 5px; |
||||
} |
} |
||||
|
</style> |
||||
</style> |
|
||||
|
|||||
@ -1,112 +1,111 @@ |
|||||
<script> |
<script> |
||||
|
import getIcon from "../common/icon" |
||||
import getIcon from "../common/icon"; |
import { store } from "../builderStore" |
||||
import {store} from "../builderStore"; |
import Button from "../common/Button.svelte" |
||||
import Button from "../common/Button.svelte"; |
import ButtonGroup from "../common/ButtonGroup.svelte" |
||||
import ButtonGroup from "../common/ButtonGroup.svelte"; |
import ActionView from "./ActionView.svelte" |
||||
import ActionView from "./ActionView.svelte"; |
import Modal from "../common/Modal.svelte" |
||||
import Modal from "../common/Modal.svelte"; |
import { pipe } from "../common/core" |
||||
import {pipe} from "../common/core"; |
import { keys, map, join } from "lodash/fp" |
||||
import {keys, map, join} from "lodash/fp"; |
|
||||
|
export let editingActionIsNew = false |
||||
export let editingActionIsNew = false; |
export let editingAction = null |
||||
export let editingAction = null; |
export let onActionEdit = action => {} |
||||
export let onActionEdit = (action) => {}; |
export let onActionDelete = action => {} |
||||
export let onActionDelete = (action) => {}; |
export let onActionSave = action => {} |
||||
export let onActionSave = (action) => {}; |
export let onActionCancel = () => {} |
||||
export let onActionCancel = () => {}; |
|
||||
|
$: isEditing = editingAction !== null |
||||
$: isEditing = (editingAction !== null); |
|
||||
|
let actionsArray = [] |
||||
let actionsArray = []; |
store.subscribe(s => { |
||||
store.subscribe(s => { |
actionsArray = pipe(s.actions, [keys, map(k => s.actions[k])]) |
||||
actionsArray = pipe(s.actions, [ |
}) |
||||
keys, |
|
||||
map(k => s.actions[k]) |
let getDefaultOptionsHtml = defaultOptions => |
||||
]); |
|
||||
}); |
|
||||
|
|
||||
let getDefaultOptionsHtml = defaultOptions => |
|
||||
pipe(defaultOptions, [ |
pipe(defaultOptions, [ |
||||
keys, |
keys, |
||||
map(k => `<span style="color:var(--slate)">${k}: </span>${JSON.stringify(defaultOptions[k])}`), |
map( |
||||
join("<br>") |
k => |
||||
]); |
`<span style="color:var(--slate)">${k}: </span>${JSON.stringify( |
||||
|
defaultOptions[k] |
||||
|
)}` |
||||
let actionEditingFinished = (action) => { |
), |
||||
|
join("<br>"), |
||||
if(action) { |
]) |
||||
onActionSave(action) |
|
||||
|
let actionEditingFinished = action => { |
||||
|
if (action) { |
||||
|
onActionSave(action) |
||||
} else { |
} else { |
||||
onActionCancel(); |
onActionCancel() |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
</script> |
</script> |
||||
|
|
||||
<h3 class="title">Actions</h3> |
<h3 class="title">Actions</h3> |
||||
|
|
||||
{#if actionsArray} |
{#if actionsArray} |
||||
<table class="fields-table uk-table uk-table-small uk-table-striped"> |
<table class="fields-table uk-table uk-table-small uk-table-striped"> |
||||
<thead> |
<thead> |
||||
<tr> |
<tr> |
||||
<th >Description</th> |
<th>Description</th> |
||||
<th>Behaviour Source</th> |
<th>Behaviour Source</th> |
||||
<th>Behaviour Name</th> |
<th>Behaviour Name</th> |
||||
<th>Default Options</th> |
<th>Default Options</th> |
||||
<th></th> |
<th /> |
||||
</tr> |
</tr> |
||||
</thead> |
</thead> |
||||
<tbody> |
<tbody> |
||||
{#each actionsArray as action} |
{#each actionsArray as action} |
||||
<tr> |
<tr> |
||||
<td class="table-content">{action.name}</td> |
<td class="table-content">{action.name}</td> |
||||
<td class="table-content">{action.behaviourSource}</td> |
<td class="table-content">{action.behaviourSource}</td> |
||||
<td class="table-content">{action.behaviourName}</td> |
<td class="table-content">{action.behaviourName}</td> |
||||
<td class="table-content">{@html getDefaultOptionsHtml(action.initialOptions)}</td> |
<td class="table-content"> |
||||
<td class="edit-button"> |
{@html getDefaultOptionsHtml(action.initialOptions)} |
||||
<span on:click={() => onActionEdit(action)}>{@html getIcon("edit")}</span> |
</td> |
||||
<span on:click={() => onActionDelete(action)}>{@html getIcon("trash")}</span> |
<td class="edit-button"> |
||||
</td> |
<span on:click={() => onActionEdit(action)}> |
||||
|
{@html getIcon('edit')} |
||||
|
</span> |
||||
|
<span on:click={() => onActionDelete(action)}> |
||||
|
{@html getIcon('trash')} |
||||
|
</span> |
||||
|
</td> |
||||
</tr> |
</tr> |
||||
{/each} |
{/each} |
||||
</tbody> |
</tbody> |
||||
</table> |
</table> |
||||
{:else} |
{:else}(no actions added){/if} |
||||
(no actions added) |
|
||||
{/if} |
|
||||
|
|
||||
|
|
||||
<Modal bind:isOpen={isEditing}> |
<Modal bind:isOpen={isEditing}> |
||||
{#if isEditing} |
{#if isEditing} |
||||
<ActionView action={editingAction} |
<ActionView |
||||
allActions={$store.actions} |
action={editingAction} |
||||
onFinished={actionEditingFinished} |
allActions={$store.actions} |
||||
isNew={editingActionIsNew}/> |
onFinished={actionEditingFinished} |
||||
{/if} |
isNew={editingActionIsNew} /> |
||||
|
{/if} |
||||
</Modal> |
</Modal> |
||||
|
|
||||
|
|
||||
<style> |
<style> |
||||
|
.edit-button { |
||||
.edit-button { |
cursor: pointer; |
||||
cursor:pointer; |
|
||||
color: var(--secondary25); |
color: var(--secondary25); |
||||
} |
} |
||||
|
|
||||
tr:hover .edit-button { |
tr:hover .edit-button { |
||||
color: var(--secondary75); |
color: var(--secondary75); |
||||
} |
} |
||||
|
|
||||
.title { |
.title { |
||||
margin: 3rem 0rem 0rem 0rem; |
margin: 3rem 0rem 0rem 0rem; |
||||
font-weight: 700; |
font-weight: 700; |
||||
} |
} |
||||
|
|
||||
.table-content { |
.table-content { |
||||
font-weight: 500; |
font-weight: 500; |
||||
font-size: .9rem; |
font-size: 0.9rem; |
||||
} |
} |
||||
|
</style> |
||||
</style> |
|
||||
|
|||||
@ -1,129 +1,130 @@ |
|||||
<script> |
<script> |
||||
|
import getIcon from "../common/icon" |
||||
import getIcon from "../common/icon"; |
import { store } from "../builderStore" |
||||
import {store} from "../builderStore"; |
import Button from "../common/Button.svelte" |
||||
import Button from "../common/Button.svelte"; |
import ButtonGroup from "../common/ButtonGroup.svelte" |
||||
import ButtonGroup from "../common/ButtonGroup.svelte"; |
import Actions from "./Actions.svelte" |
||||
import Actions from "./Actions.svelte"; |
import Triggers from "./Triggers.svelte" |
||||
import Triggers from "./Triggers.svelte"; |
import { getNewAction, getNewTrigger } from "../common/core" |
||||
import {getNewAction, getNewTrigger} from "../common/core"; |
|
||||
|
let editingAction = null |
||||
let editingAction = null; |
let editingActionIsNew = true |
||||
let editingActionIsNew = true; |
let editingTrigger = null |
||||
let editingTrigger = null; |
let editingTriggerIsNew = true |
||||
let editingTriggerIsNew = true; |
|
||||
|
let getDefaultOptionsHtml = defaultOptions => |
||||
let getDefaultOptionsHtml = defaultOptions => |
|
||||
pipe(defaultOptions, [ |
pipe(defaultOptions, [ |
||||
keys, |
keys, |
||||
map(k => `<span style="color:var(--slate)">${k}: </span>${JSON.parse(typeOptions[k])}`), |
map( |
||||
join("<br>") |
k => |
||||
]); |
`<span style="color:var(--slate)">${k}: </span>${JSON.parse( |
||||
|
typeOptions[k] |
||||
let onActionEdit = (action) => { |
)}` |
||||
editingAction = action; |
), |
||||
editingActionIsNew = false; |
join("<br>"), |
||||
} |
]) |
||||
|
|
||||
let newAction = () => { |
let onActionEdit = action => { |
||||
editingAction = getNewAction(); |
editingAction = action |
||||
editingActionIsNew = true; |
editingActionIsNew = false |
||||
} |
} |
||||
|
|
||||
let onActionDelete = (action) => { |
let newAction = () => { |
||||
store.deleteAction(action); |
editingAction = getNewAction() |
||||
} |
editingActionIsNew = true |
||||
|
} |
||||
let deleteTrigger = () => {} |
|
||||
|
let onActionDelete = action => { |
||||
let editTrigger = (trigger) => { |
store.deleteAction(action) |
||||
editingTrigger = trigger; |
} |
||||
editingTriggerIsNew = false; |
|
||||
} |
let deleteTrigger = () => {} |
||||
|
|
||||
let newTrigger = () => { |
let editTrigger = trigger => { |
||||
editingTrigger = getNewTrigger(); |
editingTrigger = trigger |
||||
editingTriggerIsNew = true; |
editingTriggerIsNew = false |
||||
} |
} |
||||
|
|
||||
let onActionSave = action => { |
let newTrigger = () => { |
||||
store.saveAction( |
editingTrigger = getNewTrigger() |
||||
action, |
editingTriggerIsNew = true |
||||
editingActionIsNew, |
} |
||||
editingAction); |
|
||||
|
let onActionSave = action => { |
||||
editingAction = null; |
store.saveAction(action, editingActionIsNew, editingAction) |
||||
} |
|
||||
|
editingAction = null |
||||
let onActionCancel = () => { |
} |
||||
editingAction = null; |
|
||||
} |
let onActionCancel = () => { |
||||
|
editingAction = null |
||||
let onTriggerSave = trigger => { |
} |
||||
store.saveTrigger( |
|
||||
trigger, |
let onTriggerSave = trigger => { |
||||
editingTriggerIsNew, |
store.saveTrigger(trigger, editingTriggerIsNew, editingTrigger) |
||||
editingTrigger); |
|
||||
|
editingTrigger = null |
||||
editingTrigger = null; |
} |
||||
} |
|
||||
|
let onTriggerCancel = () => { |
||||
let onTriggerCancel = () => { |
editingTrigger = null |
||||
editingTrigger = null; |
} |
||||
} |
|
||||
|
let onTriggerEdit = trigger => { |
||||
let onTriggerEdit = (trigger) => { |
editingTrigger = trigger |
||||
editingTrigger = trigger; |
editingTriggerIsNew = false |
||||
editingTriggerIsNew = false; |
} |
||||
} |
|
||||
|
let onTriggerDelete = trigger => { |
||||
|
store.deleteTrigger(trigger) |
||||
let onTriggerDelete = (trigger) => { |
} |
||||
store.deleteTrigger(trigger); |
|
||||
} |
|
||||
|
|
||||
</script> |
</script> |
||||
|
|
||||
<div class="root"> |
<div class="root"> |
||||
<div class="actions-header"> |
<div class="actions-header"> |
||||
<ButtonGroup> |
<ButtonGroup> |
||||
<Button color="secondary" |
<Button color="secondary" grouped on:click={newAction}> |
||||
grouped |
Create New Action |
||||
on:click={newAction}>Create New Action</Button> |
</Button> |
||||
<Button color="tertiary" |
<Button color="tertiary" grouped on:click={newTrigger}> |
||||
grouped |
Create New Trigger |
||||
on:click={newTrigger}>Create New Trigger</Button> |
</Button> |
||||
</ButtonGroup> |
</ButtonGroup> |
||||
</div> |
</div> |
||||
|
|
||||
<div class="node-view"> |
<div class="node-view"> |
||||
<Actions {editingActionIsNew} {editingAction} |
<Actions |
||||
{onActionEdit} {onActionDelete} {onActionSave} |
{editingActionIsNew} |
||||
{onActionCancel} /> |
{editingAction} |
||||
|
{onActionEdit} |
||||
<Triggers {editingTriggerIsNew} {editingTrigger} |
{onActionDelete} |
||||
{onTriggerEdit} {onTriggerDelete} {onTriggerSave} |
{onActionSave} |
||||
{onTriggerCancel} /> |
{onActionCancel} /> |
||||
</div> |
|
||||
|
<Triggers |
||||
|
{editingTriggerIsNew} |
||||
|
{editingTrigger} |
||||
|
{onTriggerEdit} |
||||
|
{onTriggerDelete} |
||||
|
{onTriggerSave} |
||||
|
{onTriggerCancel} /> |
||||
|
</div> |
||||
|
|
||||
</div> |
</div> |
||||
|
|
||||
<style> |
<style> |
||||
|
.root { |
||||
.root { |
|
||||
height: 100%; |
height: 100%; |
||||
position: relative; |
position: relative; |
||||
padding: 1.5rem; |
padding: 1.5rem; |
||||
|
} |
||||
|
|
||||
} |
.actions-header { |
||||
|
|
||||
.actions-header { |
|
||||
flex: 0 1 auto; |
flex: 0 1 auto; |
||||
} |
} |
||||
|
|
||||
.node-view { |
.node-view { |
||||
overflow-y: auto; |
overflow-y: auto; |
||||
flex: 1 1 auto; |
flex: 1 1 auto; |
||||
} |
} |
||||
|
</style> |
||||
</style> |
|
||||
|
|||||
@ -1,68 +1,71 @@ |
|||||
<script> |
<script> |
||||
|
import Textbox from "../common/Textbox.svelte" |
||||
import Textbox from "../common/Textbox.svelte"; |
import Button from "../common/Button.svelte" |
||||
import Button from "../common/Button.svelte"; |
import Dropdown from "../common/Dropdown.svelte" |
||||
import Dropdown from "../common/Dropdown.svelte"; |
import ButtonGroup from "../common/ButtonGroup.svelte" |
||||
import ButtonGroup from "../common/ButtonGroup.svelte"; |
import CodeArea from "../common/CodeArea.svelte" |
||||
import CodeArea from "../common/CodeArea.svelte"; |
import { cloneDeep, filter, keys, some, map, isUndefined } from "lodash/fp" |
||||
import {cloneDeep, filter, keys, some, |
import ErrorsBox from "../common/ErrorsBox.svelte" |
||||
map, isUndefined} from "lodash/fp"; |
import { validateTriggers, pipe, events } from "../common/core" |
||||
import ErrorsBox from "../common/ErrorsBox.svelte"; |
import getIcon from "../common/icon" |
||||
import {validateTriggers, pipe, events} from "../common/core"; |
|
||||
import getIcon from "../common/icon"; |
export let trigger |
||||
|
export let onFinished = action => {} |
||||
export let trigger; |
export let allTriggers |
||||
export let onFinished = (action) => {}; |
export let allActions |
||||
export let allTriggers; |
export let isNew = true |
||||
export let allActions; |
|
||||
export let isNew = true; |
let clonedTrigger = cloneDeep(trigger) |
||||
|
let errors = [] |
||||
let clonedTrigger = cloneDeep(trigger); |
$: actionNames = map(a => a.name)(allActions) |
||||
let errors = []; |
|
||||
$: actionNames = map(a => a.name)(allActions); |
let cancel = () => onFinished() |
||||
|
let save = () => { |
||||
let cancel = () => onFinished(); |
|
||||
let save = () => { |
|
||||
const newTriggersList = [ |
const newTriggersList = [ |
||||
...pipe(allTriggers ,[filter(t => t !== trigger)]), |
...pipe(allTriggers, [filter(t => t !== trigger)]), |
||||
clonedTrigger] |
clonedTrigger, |
||||
|
] |
||||
errors = validateTriggers(newTriggersList, allActions); |
|
||||
|
|
||||
const test = map(t =>(!t.actionName || some(a => a.name === t.actionName)(allActions)))(newTriggersList) |
errors = validateTriggers(newTriggersList, allActions) |
||||
|
|
||||
if(errors.length === 0) |
const test = map( |
||||
onFinished(clonedTrigger); |
t => !t.actionName || some(a => a.name === t.actionName)(allActions) |
||||
} |
)(newTriggersList) |
||||
|
|
||||
|
if (errors.length === 0) onFinished(clonedTrigger) |
||||
|
} |
||||
</script> |
</script> |
||||
|
|
||||
<div> |
<div> |
||||
|
|
||||
<ErrorsBox {errors} style="margin-bottom:20px"/> |
<ErrorsBox {errors} style="margin-bottom:20px" /> |
||||
|
|
||||
|
<form class="uk-form-horizontal"> |
||||
|
|
||||
<form class="uk-form-horizontal"> |
<Dropdown |
||||
|
label="Event" |
||||
<Dropdown label="Event" |
options={['', ...events]} |
||||
options={["",...events]} |
bind:selected={clonedTrigger.eventName} /> |
||||
bind:selected={clonedTrigger.eventName} /> |
<Dropdown |
||||
<Dropdown label="Action" |
label="Action" |
||||
options={["",...actionNames]} |
options={['', ...actionNames]} |
||||
bind:selected={clonedTrigger.actionName} /> |
bind:selected={clonedTrigger.actionName} /> |
||||
<CodeArea label="Condition (javascript)" |
<CodeArea |
||||
bind:text={clonedTrigger.condition} /> |
label="Condition (javascript)" |
||||
<CodeArea label="Action Options Creator (javascript)" |
bind:text={clonedTrigger.condition} /> |
||||
bind:text={clonedTrigger.optionsCreator} /> |
<CodeArea |
||||
|
label="Action Options Creator (javascript)" |
||||
|
bind:text={clonedTrigger.optionsCreator} /> |
||||
|
|
||||
</form> |
</form> |
||||
|
|
||||
<ButtonGroup> |
<ButtonGroup> |
||||
<Button color="primary" grouped on:click={save}>Save</Button> |
<Button color="primary" grouped on:click={save}>Save</Button> |
||||
<Button color="tertiary" grouped on:click={cancel}>Cancel</Button> |
<Button color="tertiary" grouped on:click={cancel}>Cancel</Button> |
||||
</ButtonGroup> |
</ButtonGroup> |
||||
|
|
||||
</div> |
</div> |
||||
|
|
||||
<style> |
<style> |
||||
|
|
||||
</style> |
</style> |
||||
|
|||||
@ -1,94 +1,90 @@ |
|||||
<script> |
<script> |
||||
|
import { store } from "../builderStore" |
||||
import {store} from "../builderStore"; |
import getIcon from "../common/icon" |
||||
import getIcon from "../common/icon"; |
import Button from "../common/Button.svelte" |
||||
import Button from "../common/Button.svelte"; |
import Modal from "../common/Modal.svelte" |
||||
import Modal from "../common/Modal.svelte"; |
import TriggerView from "./TriggerView.svelte" |
||||
import TriggerView from "./TriggerView.svelte"; |
|
||||
|
export let editingTrigger = null |
||||
|
export let editingTriggerIsNew = true |
||||
export let editingTrigger = null; |
export let onTriggerEdit = trigger => {} |
||||
export let editingTriggerIsNew = true; |
export let onTriggerDelete = trigger => {} |
||||
export let onTriggerEdit = (trigger) => {}; |
export let onTriggerSave = trigger => {} |
||||
export let onTriggerDelete = (trigger) => {}; |
export let onTriggerCancel = () => {} |
||||
export let onTriggerSave = (trigger) => {}; |
|
||||
export let onTriggerCancel = () => {}; |
$: isEditing = editingTrigger !== null |
||||
|
|
||||
$: isEditing = (editingTrigger !== null); |
let triggerEditingFinished = trigger => { |
||||
|
if (trigger) { |
||||
let triggerEditingFinished = (trigger) => { |
onTriggerSave(trigger) |
||||
|
|
||||
if(trigger) { |
|
||||
onTriggerSave(trigger) |
|
||||
} else { |
} else { |
||||
onTriggerCancel(); |
onTriggerCancel() |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
</script> |
</script> |
||||
|
|
||||
<h3 class="title">Triggers</h3> |
<h3 class="title">Triggers</h3> |
||||
|
|
||||
{#if $store.triggers} |
{#if $store.triggers} |
||||
<table class="fields-table uk-table uk-table-small uk-table-striped"> |
<table class="fields-table uk-table uk-table-small uk-table-striped"> |
||||
<thead> |
<thead> |
||||
<tr> |
<tr> |
||||
<th>Event</th> |
<th>Event</th> |
||||
<th>Action</th> |
<th>Action</th> |
||||
<th>Condition</th> |
<th>Condition</th> |
||||
<th>Create Options</th> |
<th>Create Options</th> |
||||
<th></th> |
<th /> |
||||
</tr> |
</tr> |
||||
</thead> |
</thead> |
||||
<tbody> |
<tbody> |
||||
{#each $store.triggers as trigger} |
{#each $store.triggers as trigger} |
||||
<tr> |
<tr> |
||||
<td class="table-content">{trigger.eventName}</td> |
<td class="table-content">{trigger.eventName}</td> |
||||
<td class="table-content">{trigger.actionName}</td> |
<td class="table-content">{trigger.actionName}</td> |
||||
<td class="table-content">{trigger.condition}</td> |
<td class="table-content">{trigger.condition}</td> |
||||
<td class="table-content">{trigger.optionsCreator}</td> |
<td class="table-content">{trigger.optionsCreator}</td> |
||||
<td class="edit-button"> |
<td class="edit-button"> |
||||
<span on:click={() => onTriggerEdit(trigger)}>{@html getIcon("edit")}</span> |
<span on:click={() => onTriggerEdit(trigger)}> |
||||
<span on:click={() => onTriggerDelete(trigger)}>{@html getIcon("trash")}</span> |
{@html getIcon('edit')} |
||||
</td> |
</span> |
||||
|
<span on:click={() => onTriggerDelete(trigger)}> |
||||
|
{@html getIcon('trash')} |
||||
|
</span> |
||||
|
</td> |
||||
</tr> |
</tr> |
||||
{/each} |
{/each} |
||||
</tbody> |
</tbody> |
||||
</table> |
</table> |
||||
{:else} |
{:else}(no triggers added){/if} |
||||
(no triggers added) |
|
||||
{/if} |
|
||||
|
|
||||
|
|
||||
<Modal bind:isOpen={isEditing}> |
<Modal bind:isOpen={isEditing}> |
||||
{#if isEditing} |
{#if isEditing} |
||||
<TriggerView trigger={editingTrigger} |
<TriggerView |
||||
allActions={$store.actions} |
trigger={editingTrigger} |
||||
allTriggers={$store.triggers} |
allActions={$store.actions} |
||||
onFinished={triggerEditingFinished} |
allTriggers={$store.triggers} |
||||
isNew={editingTriggerIsNew}/> |
onFinished={triggerEditingFinished} |
||||
{/if} |
isNew={editingTriggerIsNew} /> |
||||
|
{/if} |
||||
</Modal> |
</Modal> |
||||
|
|
||||
<style> |
<style> |
||||
|
.edit-button { |
||||
.edit-button { |
cursor: pointer; |
||||
cursor:pointer; |
|
||||
color: var(--secondary25); |
color: var(--secondary25); |
||||
} |
} |
||||
|
|
||||
.title { |
.title { |
||||
margin: 3rem 0rem 0rem 0rem; |
margin: 3rem 0rem 0rem 0rem; |
||||
font-weight: 700; |
font-weight: 700; |
||||
} |
} |
||||
|
|
||||
.table-content { |
.table-content { |
||||
font-weight: 500; |
font-weight: 500; |
||||
font-size: .9rem; |
font-size: 0.9rem; |
||||
} |
} |
||||
|
|
||||
tr:hover .edit-button { |
tr:hover .edit-button { |
||||
color: var(--secondary75); |
color: var(--secondary75); |
||||
} |
} |
||||
|
</style> |
||||
</style> |
|
||||
|
|||||
@ -1,163 +1,167 @@ |
|||||
<script> |
<script> |
||||
|
export let color = "primary" |
||||
|
export let className = "" |
||||
|
export let style = "" |
||||
|
export let groupPosition = "" |
||||
|
export let grouped = false |
||||
|
|
||||
export let color = "primary"; |
$: borderClass = grouped ? "" : "border-normal" |
||||
export let className = ""; |
|
||||
export let style = ""; |
|
||||
export let groupPosition = ""; |
|
||||
export let grouped = false; |
|
||||
|
|
||||
$: borderClass = grouped |
|
||||
? "" |
|
||||
: "border-normal"; |
|
||||
|
|
||||
</script> |
</script> |
||||
|
|
||||
<button class="{color} {className} {borderClass} {grouped ? "grouped" : ""}" |
<button |
||||
style="{style}" |
class="{color} |
||||
on:click > |
{className} |
||||
<slot/> |
{borderClass} |
||||
|
{grouped ? 'grouped' : ''}" |
||||
|
{style} |
||||
|
on:click> |
||||
|
<slot /> |
||||
</button> |
</button> |
||||
|
|
||||
<style> |
<style> |
||||
|
.border-normal { |
||||
.border-normal { border-radius: var(--borderradiusall); } |
border-radius: var(--borderradiusall); |
||||
.border-left { border-radius: var(--borderradius) 0 0 var(--borderradius); } |
} |
||||
.border-right { border-radius: 0 var(--borderradius) var(--borderradius) 0; } |
.border-left { |
||||
.border-middle { border-radius: 0; } |
border-radius: var(--borderradius) 0 0 var(--borderradius); |
||||
|
} |
||||
button { |
.border-right { |
||||
border-style: solid; |
border-radius: 0 var(--borderradius) var(--borderradius) 0; |
||||
|
} |
||||
|
.border-middle { |
||||
|
border-radius: 0; |
||||
|
} |
||||
|
|
||||
|
button { |
||||
|
border-style: solid; |
||||
padding: 7.5px 15px; |
padding: 7.5px 15px; |
||||
cursor:pointer; |
cursor: pointer; |
||||
margin:5px; |
margin: 5px; |
||||
border-radius: 5px; |
border-radius: 5px; |
||||
} |
} |
||||
|
|
||||
/* ---- PRIMARY ----*/ |
/* ---- PRIMARY ----*/ |
||||
.primary { |
.primary { |
||||
background-color: var(--primary100); |
background-color: var(--primary100); |
||||
border-color: var(--primary100); |
border-color: var(--primary100); |
||||
color: var(--white); |
color: var(--white); |
||||
} |
} |
||||
|
|
||||
.primary:hover { |
.primary:hover { |
||||
background-color: var(--primary75); |
background-color: var(--primary75); |
||||
border-color: var(--primary75); |
border-color: var(--primary75); |
||||
} |
} |
||||
|
|
||||
.primary:active { |
.primary:active { |
||||
background-color: var(--primarydark); |
background-color: var(--primarydark); |
||||
border-color: var(--primarydark); |
border-color: var(--primarydark); |
||||
} |
} |
||||
|
|
||||
.primary-outline { |
.primary-outline { |
||||
background-color: var(--white); |
background-color: var(--white); |
||||
border-color: var(--primary100); |
border-color: var(--primary100); |
||||
color: var(--primary100); |
color: var(--primary100); |
||||
} |
} |
||||
|
|
||||
.primary-outline:hover { |
.primary-outline:hover { |
||||
background-color: var(--primary10); |
background-color: var(--primary10); |
||||
} |
} |
||||
|
|
||||
.primary-outline:pressed { |
.primary-outline:pressed { |
||||
background-color: var(--primary25); |
background-color: var(--primary25); |
||||
} |
} |
||||
|
|
||||
/* ---- secondary ----*/ |
/* ---- secondary ----*/ |
||||
|
|
||||
.secondary { |
.secondary { |
||||
background-color: var(--secondary100); |
background-color: var(--secondary100); |
||||
border-color: var(--secondary100); |
border-color: var(--secondary100); |
||||
color: var(--white); |
color: var(--white); |
||||
} |
} |
||||
|
|
||||
.secondary:hover { |
.secondary:hover { |
||||
background-color: var(--secondary75); |
background-color: var(--secondary75); |
||||
border-color: var(--secondary75); |
border-color: var(--secondary75); |
||||
} |
} |
||||
|
|
||||
.secondary:pressed { |
.secondary:pressed { |
||||
background-color: var(--secondarydark); |
background-color: var(--secondarydark); |
||||
border-color: var(--secondarydark); |
border-color: var(--secondarydark); |
||||
} |
} |
||||
|
|
||||
.secondary-outline { |
.secondary-outline { |
||||
background-color: var(--white); |
background-color: var(--white); |
||||
border-color: var(--secondary100); |
border-color: var(--secondary100); |
||||
color: var(--secondary100); |
color: var(--secondary100); |
||||
} |
} |
||||
|
|
||||
.secondary-outline:hover { |
.secondary-outline:hover { |
||||
background-color: var(--secondary10); |
background-color: var(--secondary10); |
||||
} |
} |
||||
|
|
||||
.secondary-outline:pressed { |
.secondary-outline:pressed { |
||||
background-color: var(--secondary25); |
background-color: var(--secondary25); |
||||
} |
} |
||||
|
|
||||
|
/* ---- success ----*/ |
||||
/* ---- success ----*/ |
.success { |
||||
.success { |
|
||||
background-color: var(--success100); |
background-color: var(--success100); |
||||
border-color: var(--success100); |
border-color: var(--success100); |
||||
color: var(--white); |
color: var(--white); |
||||
} |
} |
||||
|
|
||||
.success:hover { |
.success:hover { |
||||
background-color: var(--success75); |
background-color: var(--success75); |
||||
border-color: var(--success75); |
border-color: var(--success75); |
||||
} |
} |
||||
|
|
||||
.success:pressed { |
.success:pressed { |
||||
background-color: var(--successdark); |
background-color: var(--successdark); |
||||
border-color: var(--successdark); |
border-color: var(--successdark); |
||||
} |
} |
||||
|
|
||||
.success-outline { |
.success-outline { |
||||
background-color: var(--white); |
background-color: var(--white); |
||||
border-color: var(--success100); |
border-color: var(--success100); |
||||
color: var(--success100); |
color: var(--success100); |
||||
} |
} |
||||
|
|
||||
.success-outline:hover { |
.success-outline:hover { |
||||
background-color: var(--success10); |
background-color: var(--success10); |
||||
} |
} |
||||
|
|
||||
.success-outline:pressed { |
.success-outline:pressed { |
||||
background-color: var(--success25); |
background-color: var(--success25); |
||||
} |
} |
||||
|
|
||||
/* ---- deletion ----*/ |
/* ---- deletion ----*/ |
||||
.deletion { |
.deletion { |
||||
background-color: var(--deletion100); |
background-color: var(--deletion100); |
||||
border-color: var(--deletion100); |
border-color: var(--deletion100); |
||||
color: var(--white); |
color: var(--white); |
||||
} |
} |
||||
|
|
||||
.deletion:hover { |
.deletion:hover { |
||||
background-color: var(--deletion75); |
background-color: var(--deletion75); |
||||
border-color: var(--deletion75); |
border-color: var(--deletion75); |
||||
} |
} |
||||
|
|
||||
.deletion:pressed { |
.deletion:pressed { |
||||
background-color: var(--deletiondark); |
background-color: var(--deletiondark); |
||||
border-color: var(--deletiondark); |
border-color: var(--deletiondark); |
||||
} |
} |
||||
|
|
||||
.deletion-outline { |
.deletion-outline { |
||||
background-color: var(--white); |
background-color: var(--white); |
||||
border-color: var(--deletion100); |
border-color: var(--deletion100); |
||||
color: var(--deletion100); |
color: var(--deletion100); |
||||
} |
} |
||||
|
|
||||
.deletion-outline:hover { |
.deletion-outline:hover { |
||||
background-color: var(--deletion10); |
background-color: var(--deletion10); |
||||
} |
} |
||||
|
|
||||
.deletion-outline:pressed { |
.deletion-outline:pressed { |
||||
background-color: var(--deletion25); |
background-color: var(--deletion25); |
||||
} |
} |
||||
|
</style> |
||||
|
|
||||
</style> |
|
||||
|
|||||
@ -1,27 +1,25 @@ |
|||||
<script> |
<script> |
||||
export let style=""; |
export let style = "" |
||||
</script> |
</script> |
||||
|
|
||||
<div class="root" style={style}> |
<div class="root" {style}> |
||||
<slot /> |
<slot /> |
||||
</div> |
</div> |
||||
|
|
||||
<style> |
<style> |
||||
|
.root { |
||||
.root { |
|
||||
display: flex; |
display: flex; |
||||
} |
} |
||||
|
|
||||
.root:last-child { |
.root:last-child { |
||||
border-radius: 0 var(--borderradius) var(--borderradius) 0; |
border-radius: 0 var(--borderradius) var(--borderradius) 0; |
||||
} |
} |
||||
|
|
||||
.root:first-child { |
.root:first-child { |
||||
border-radius: var(--borderradius) 0 0 var(--borderradius); |
border-radius: var(--borderradius) 0 0 var(--borderradius); |
||||
} |
} |
||||
|
|
||||
.root:not(:first-child):not(:last-child) { |
.root:not(:first-child):not(:last-child) { |
||||
border-radius: 0; |
border-radius: 0; |
||||
} |
} |
||||
|
</style> |
||||
</style> |
|
||||
|
|||||
@ -1,16 +1,13 @@ |
|||||
<script> |
<script> |
||||
|
export let checked = false |
||||
export let checked=false; |
export let label = "" |
||||
export let label=""; |
|
||||
|
|
||||
</script> |
</script> |
||||
|
|
||||
<input class="uk-checkbox" type="checkbox" bind:checked on:change />{label} |
<input class="uk-checkbox" type="checkbox" bind:checked on:change /> |
||||
|
{label} |
||||
|
|
||||
<style> |
<style> |
||||
|
input { |
||||
input { |
margin-right: 7px; |
||||
margin-right:7px; |
} |
||||
} |
</style> |
||||
|
|
||||
</style> |
|
||||
|
|||||
@ -1,24 +1,22 @@ |
|||||
<script> |
<script> |
||||
// todo: use https://ace.c9.io |
// todo: use https://ace.c9.io |
||||
export let text = ""; |
export let text = "" |
||||
export let label = ""; |
export let label = "" |
||||
</script> |
</script> |
||||
|
|
||||
<div>{label}</div> |
<div>{label}</div> |
||||
<textarea class="uk-textarea" bind:value={text}></textarea> |
<textarea class="uk-textarea" bind:value={text} /> |
||||
|
|
||||
<style> |
<style> |
||||
|
textarea { |
||||
textarea { |
padding: 3px; |
||||
padding:3px; |
margin-top: 5px; |
||||
margin-top:5px; |
margin-bottom: 10px; |
||||
margin-bottom:10px; |
|
||||
background: var(--lightslate); |
background: var(--lightslate); |
||||
color: var(--white); |
color: var(--white); |
||||
font-family: 'Courier New', Courier, monospace; |
font-family: "Courier New", Courier, monospace; |
||||
width:95%; |
width: 95%; |
||||
height:100px; |
height: 100px; |
||||
border-radius: 5px; |
border-radius: 5px; |
||||
} |
} |
||||
|
</style> |
||||
</style> |
|
||||
|
|||||
@ -1,17 +1,13 @@ |
|||||
<script> |
<script> |
||||
|
export let name = "" |
||||
export let name = ""; |
|
||||
|
|
||||
</script> |
</script> |
||||
|
|
||||
<div> |
<div> |
||||
<h4>Coming Sometime: {name}</h4> |
<h4>Coming Sometime: {name}</h4> |
||||
</div> |
</div> |
||||
|
|
||||
<style> |
<style> |
||||
|
h4 { |
||||
h4 { |
|
||||
margin-top: 20px; |
margin-top: 20px; |
||||
} |
} |
||||
|
</style> |
||||
</style> |
|
||||
|
|||||
@ -1,39 +1,44 @@ |
|||||
<script> |
<script> |
||||
import {createEventDispatcher} from "svelte"; |
import { createEventDispatcher } from "svelte" |
||||
|
|
||||
export let selected; |
export let selected |
||||
export let label; |
export let label |
||||
export let options; |
export let options |
||||
export let valueMember; |
export let valueMember |
||||
export let textMember; |
export let textMember |
||||
export let multiple=false; |
export let multiple = false |
||||
export let width = "medium"; |
export let width = "medium" |
||||
export let size = "small"; |
export let size = "small" |
||||
|
|
||||
const dispatch =createEventDispatcher(); |
const dispatch = createEventDispatcher() |
||||
|
|
||||
|
|
||||
</script> |
</script> |
||||
|
|
||||
|
|
||||
<div class="uk-margin"> |
<div class="uk-margin"> |
||||
<label class="uk-form-label">{label}</label> |
<label class="uk-form-label">{label}</label> |
||||
<div class="uk-form-controls"> |
<div class="uk-form-controls"> |
||||
{#if multiple} |
{#if multiple} |
||||
|
<select |
||||
<select class="uk-select uk-form-width-{width} uk-form-{size}" multiple bind:value={selected} on:change> |
class="uk-select uk-form-width-{width} uk-form-{size}" |
||||
{#each options as option} |
multiple |
||||
<option value={!valueMember ? option : valueMember(option)}>{!textMember ? option : textMember(option)}</option> |
bind:value={selected} |
||||
{/each} |
on:change> |
||||
</select> |
{#each options as option} |
||||
|
<option value={!valueMember ? option : valueMember(option)}> |
||||
{:else} |
{!textMember ? option : textMember(option)} |
||||
|
</option> |
||||
<select class="uk-select uk-form-width-{width} uk-form-{size}" bind:value={selected} on:change> |
{/each} |
||||
{#each options as option} |
</select> |
||||
<option value={!valueMember ? option : valueMember(option)}>{!textMember ? option : textMember(option)}</option> |
{:else} |
||||
{/each} |
<select |
||||
</select> |
class="uk-select uk-form-width-{width} uk-form-{size}" |
||||
{/if} |
bind:value={selected} |
||||
</div> |
on:change> |
||||
|
{#each options as option} |
||||
|
<option value={!valueMember ? option : valueMember(option)}> |
||||
|
{!textMember ? option : textMember(option)} |
||||
|
</option> |
||||
|
{/each} |
||||
|
</select> |
||||
|
{/if} |
||||
|
</div> |
||||
</div> |
</div> |
||||
|
|||||
@ -1,68 +1,65 @@ |
|||||
<script> |
<script> |
||||
|
import getIcon from "./icon" |
||||
import getIcon from "./icon"; |
export let iconName |
||||
export let iconName; |
export let actions = [] // [ {label: "Action Name", onclick: () => {...} } ] |
||||
export let actions = []; // [ {label: "Action Name", onclick: () => {...} } ] |
let isDroppedDown = false |
||||
let isDroppedDown = false; |
|
||||
|
|
||||
</script> |
</script> |
||||
|
|
||||
|
<div class="root" on:click={() => (isDroppedDown = !isDroppedDown)}> |
||||
|
{@html getIcon(iconName)} |
||||
|
|
||||
<div class="root" on:click={() => isDroppedDown = !isDroppedDown}> |
<div |
||||
{@html getIcon(iconName)} |
class="dropdown-background" |
||||
|
on:click|stopPropagation={() => (isDroppedDown = false)} |
||||
<div class="dropdown-background" on:click|stopPropagation={() => isDroppedDown = false} style="display: {isDroppedDown ? 'block' : 'none'}"></div> |
style="display: {isDroppedDown ? 'block' : 'none'}" /> |
||||
|
|
||||
<div class="dropdown-content" style="display: {isDroppedDown ? 'inline-block' : 'none'}"> |
<div |
||||
{#each actions as action} |
class="dropdown-content" |
||||
<div class="action-row" on:click={action.onclick}> |
style="display: {isDroppedDown ? 'inline-block' : 'none'}"> |
||||
{action.label} |
{#each actions as action} |
||||
</div> |
<div class="action-row" on:click={action.onclick}>{action.label}</div> |
||||
{/each} |
{/each} |
||||
</div> |
</div> |
||||
|
|
||||
</div> |
|
||||
|
|
||||
|
</div> |
||||
|
|
||||
<style> |
<style> |
||||
|
.dropdown-background { |
||||
.dropdown-background { |
|
||||
position: fixed; |
position: fixed; |
||||
top:0; |
top: 0; |
||||
left:0; |
left: 0; |
||||
width:100vw; |
width: 100vw; |
||||
height:100vh; |
height: 100vh; |
||||
} |
} |
||||
|
|
||||
.root { |
.root { |
||||
cursor: pointer; |
cursor: pointer; |
||||
z-index: 1; |
z-index: 1; |
||||
} |
} |
||||
|
|
||||
.dropdown-content { |
.dropdown-content { |
||||
position: absolute; |
position: absolute; |
||||
background-color: var(--white); |
background-color: var(--white); |
||||
min-width: 160px; |
min-width: 160px; |
||||
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); |
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2); |
||||
z-index: 1; |
z-index: 1; |
||||
font-weight: normal; |
font-weight: normal; |
||||
border-style: solid; |
border-style: solid; |
||||
border-width: 1px; |
border-width: 1px; |
||||
border-color: var(--secondary10); |
border-color: var(--secondary10); |
||||
} |
} |
||||
|
|
||||
.dropdown-content:not(:focus) { |
.dropdown-content:not(:focus) { |
||||
display: none; |
display: none; |
||||
} |
} |
||||
|
|
||||
.action-row { |
.action-row { |
||||
padding: 7px 10px; |
padding: 7px 10px; |
||||
cursor:pointer; |
cursor: pointer; |
||||
} |
} |
||||
|
|
||||
.action-row:hover { |
.action-row:hover { |
||||
background-color: var(--primary100); |
background-color: var(--primary100); |
||||
color:var(--white); |
color: var(--white); |
||||
} |
} |
||||
|
</style> |
||||
</style> |
|
||||
|
|||||
@ -1,29 +1,29 @@ |
|||||
<script> |
<script> |
||||
export let errors = []; |
export let errors = [] |
||||
|
|
||||
$:hasErrors = errors.length > 0; |
$: hasErrors = errors.length > 0 |
||||
</script> |
</script> |
||||
|
|
||||
{#if hasErrors} |
{#if hasErrors} |
||||
<div class="error-container"> |
<div class="error-container"> |
||||
{#each errors as error} |
{#each errors as error} |
||||
<div class="error-row">{error.field ? `${error.field}: ` : ""}{error.error}</div> |
<div class="error-row"> |
||||
|
{error.field ? `${error.field}: ` : ''}{error.error} |
||||
|
</div> |
||||
{/each} |
{/each} |
||||
</div> |
</div> |
||||
{/if} |
{/if} |
||||
|
|
||||
<style> |
<style> |
||||
|
.error-container { |
||||
.error-container { |
padding: 10px; |
||||
padding:10px; |
|
||||
border-style: solid; |
border-style: solid; |
||||
border-color: var(--deletion100); |
border-color: var(--deletion100); |
||||
border-radius: var(--borderradiusall); |
border-radius: var(--borderradiusall); |
||||
background: var(--deletion75); |
background: var(--deletion75); |
||||
} |
} |
||||
|
|
||||
.error-row { |
.error-row { |
||||
padding: 5px 0px; |
padding: 5px 0px; |
||||
} |
} |
||||
|
</style> |
||||
</style> |
|
||||
|
|||||
@ -1,63 +1,59 @@ |
|||||
<script> |
<script> |
||||
import getIcon from "./icon"; |
import getIcon from "./icon" |
||||
|
|
||||
export let size = 18; |
export let size = 18 |
||||
export let icon = ""; |
export let icon = "" |
||||
export let style = ""; |
export let style = "" |
||||
export let color = "var(--secondary100)"; |
export let color = "var(--secondary100)" |
||||
export let hoverColor = "var(--secondary75)"; |
export let hoverColor = "var(--secondary75)" |
||||
export let attributes = {}; |
export let attributes = {} |
||||
|
|
||||
let currentAttributes = []; |
let currentAttributes = [] |
||||
const addAttributes = (node, attributes) => { |
const addAttributes = (node, attributes) => { |
||||
|
const add = _attributes => { |
||||
const add = (_attributes) => { |
const attrs = [] |
||||
const attrs = []; |
for (let attr in _attributes) { |
||||
for(let attr in _attributes) { |
node.setAttribute(attr, _attributes[attr]) |
||||
node.setAttribute(attr, _attributes[attr]); |
attrs.push("uk-toggle") |
||||
attrs.push("uk-toggle") |
} |
||||
} |
currentAttributes = attrs |
||||
currentAttributes = attrs; |
|
||||
} |
} |
||||
|
|
||||
add(attributes); |
add(attributes) |
||||
|
|
||||
return { |
return { |
||||
// should implement update method |
// should implement update method |
||||
update(attributes) { |
update(attributes) { |
||||
for(let attr of currentAttributes) { |
for (let attr of currentAttributes) { |
||||
node.removeAttribute(attr) |
node.removeAttribute(attr) |
||||
} |
} |
||||
add(attributes); |
add(attributes) |
||||
}, |
}, |
||||
destroy() {} |
destroy() {}, |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
</script> |
</script> |
||||
|
|
||||
<button style="{style}{style ? ";" : ""} color:{color}; --hovercolor:{hoverColor}" |
<button |
||||
on:click |
style="{style}{style ? ';' : ''} color:{color}; --hovercolor:{hoverColor}" |
||||
use:addAttributes={attributes}> |
on:click |
||||
{@html getIcon(icon, size)} |
use:addAttributes={attributes}> |
||||
|
{@html getIcon(icon, size)} |
||||
</button> |
</button> |
||||
|
|
||||
|
|
||||
<style> |
<style> |
||||
|
button { |
||||
button { |
|
||||
border-style: none; |
border-style: none; |
||||
background-color: rgba(0,0,0,0); |
background-color: rgba(0, 0, 0, 0); |
||||
cursor: pointer; |
cursor: pointer; |
||||
outline:none; |
outline: none; |
||||
} |
} |
||||
|
|
||||
button:hover { |
button:hover { |
||||
color: var(--hovercolor); |
color: var(--hovercolor); |
||||
} |
} |
||||
|
|
||||
button:active { |
|
||||
outline:none; |
|
||||
} |
|
||||
|
|
||||
</style> |
button:active { |
||||
|
outline: none; |
||||
|
} |
||||
|
</style> |
||||
|
|||||
|
Before Width: | Height: | Size: 228 B After Width: | Height: | Size: 246 B |
|
Before Width: | Height: | Size: 158 B After Width: | Height: | Size: 157 B |
|
Before Width: | Height: | Size: 400 B After Width: | Height: | Size: 430 B |
|
Before Width: | Height: | Size: 339 B After Width: | Height: | Size: 365 B |
|
Before Width: | Height: | Size: 280 B After Width: | Height: | Size: 305 B |
|
Before Width: | Height: | Size: 415 B After Width: | Height: | Size: 448 B |
|
Before Width: | Height: | Size: 446 B After Width: | Height: | Size: 447 B |
|
Before Width: | Height: | Size: 346 B After Width: | Height: | Size: 372 B |
@ -1,35 +1,30 @@ |
|||||
<script> |
<script> |
||||
import {join} from "lodash/fp"; |
import { join } from "lodash/fp" |
||||
|
|
||||
export let values; |
export let values |
||||
export let label; |
export let label |
||||
|
|
||||
const inputChanged = ev => { |
const inputChanged = ev => { |
||||
try { |
try { |
||||
values = ev.target.value.split("\n"); |
values = ev.target.value.split("\n") |
||||
} catch(_) { |
} catch (_) { |
||||
values = []; |
values = [] |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
$: valuesText = join("\n")(values); |
|
||||
|
|
||||
|
|
||||
|
$: valuesText = join("\n")(values) |
||||
</script> |
</script> |
||||
|
|
||||
|
|
||||
<div class="uk-margin"> |
<div class="uk-margin"> |
||||
<label class="uk-form-label">{label}</label> |
<label class="uk-form-label">{label}</label> |
||||
<div class="uk-form-controls"> |
<div class="uk-form-controls"> |
||||
<textarea value={valuesText} on:change={inputChanged} ></textarea> |
<textarea value={valuesText} on:change={inputChanged} /> |
||||
</div> |
</div> |
||||
</div> |
</div> |
||||
|
|
||||
<style> |
<style> |
||||
|
textarea { |
||||
textarea { |
width: 300px; |
||||
width:300px; |
height: 200px; |
||||
height:200px; |
} |
||||
} |
</style> |
||||
|
|
||||
</style> |
|
||||
|
|||||
@ -1,62 +1,59 @@ |
|||||
<script> |
<script> |
||||
import Button from "../common/Button.svelte"; |
import Button from "../common/Button.svelte" |
||||
import ButtonGroup from "../common/ButtonGroup.svelte"; |
import ButtonGroup from "../common/ButtonGroup.svelte" |
||||
import {store} from "../builderStore"; |
import { store } from "../builderStore" |
||||
import Modal from "../common/Modal.svelte"; |
import Modal from "../common/Modal.svelte" |
||||
import ErrorsBox from "../common/ErrorsBox.svelte"; |
import ErrorsBox from "../common/ErrorsBox.svelte" |
||||
|
|
||||
export let left; |
export let left |
||||
let confirmDelete = false; |
let confirmDelete = false |
||||
const openConfirmDelete = () => { |
const openConfirmDelete = () => { |
||||
confirmDelete = true; |
confirmDelete = true |
||||
} |
} |
||||
|
|
||||
const deleteCurrentNode = () => { |
const deleteCurrentNode = () => { |
||||
confirmDelete = false; |
confirmDelete = false |
||||
store.deleteCurrentNode(); |
store.deleteCurrentNode() |
||||
} |
} |
||||
|
|
||||
</script> |
</script> |
||||
|
|
||||
<div class="root" style="left: {left}"> |
<div class="root" style="left: {left}"> |
||||
|
|
||||
<ButtonGroup> |
<ButtonGroup> |
||||
<Button color="secondary" grouped on:click={store.saveCurrentNode}> |
<Button color="secondary" grouped on:click={store.saveCurrentNode}> |
||||
{#if $store.currentNodeIsNew} |
{#if $store.currentNodeIsNew}Create{:else}Update{/if} |
||||
Create |
</Button> |
||||
{:else} |
|
||||
Update |
{#if !$store.currentNodeIsNew} |
||||
{/if} |
<Button color="tertiary" grouped on:click={openConfirmDelete}> |
||||
</Button> |
Delete |
||||
|
</Button> |
||||
{#if !$store.currentNodeIsNew} |
{/if} |
||||
<Button color="tertiary" grouped on:click={openConfirmDelete}> |
</ButtonGroup> |
||||
Delete |
|
||||
</Button> |
{#if !!$store.errors && $store.errors.length > 0} |
||||
{/if} |
|
||||
</ButtonGroup> |
|
||||
|
|
||||
{#if !!$store.errors && $store.errors.length > 0} |
|
||||
<div style="width: 500px"> |
<div style="width: 500px"> |
||||
<ErrorsBox errors={$store.errors}/> |
<ErrorsBox errors={$store.errors} /> |
||||
</div> |
</div> |
||||
{/if} |
{/if} |
||||
|
|
||||
<Modal bind:isOpen={confirmDelete}> |
<Modal bind:isOpen={confirmDelete}> |
||||
<div style="margin: 10px 0px 20px 0px">Are you sure you want to delete {$store.currentNode.name} ?</div> |
<div style="margin: 10px 0px 20px 0px"> |
||||
<div style="float:right"> |
Are you sure you want to delete {$store.currentNode.name} ? |
||||
<Button color="primary" on:click={deleteCurrentNode}>Yes</Button> |
</div> |
||||
<Button color="secondary" on:click={() => confirmDelete = false}>No</Button> |
<div style="float:right"> |
||||
</div> |
<Button color="primary" on:click={deleteCurrentNode}>Yes</Button> |
||||
</Modal> |
<Button color="secondary" on:click={() => (confirmDelete = false)}> |
||||
|
No |
||||
|
</Button> |
||||
|
</div> |
||||
|
</Modal> |
||||
</div> |
</div> |
||||
|
|
||||
<style> |
<style> |
||||
|
.root { |
||||
.root { |
|
||||
padding: 1.5rem; |
padding: 1.5rem; |
||||
width: 100%; |
width: 100%; |
||||
align-items: right; |
align-items: right; |
||||
} |
} |
||||
|
</style> |
||||
</style> |
|
||||
|
|||||
@ -1,20 +1,16 @@ |
|||||
<script> |
<script> |
||||
|
import RecordCard from "./RecordCard.svelte" |
||||
|
|
||||
import RecordCard from "./RecordCard.svelte"; |
export let record = {} |
||||
|
|
||||
export let record = {}; |
|
||||
|
|
||||
</script> |
</script> |
||||
|
|
||||
<div class="root"> |
<div class="root"> |
||||
<div class="title">{record.name}</div> |
<div class="title">{record.name}</div> |
||||
<div class="inner"> |
<div class="inner"> |
||||
<div class="node-path">{record.nodeKey()}</div> |
<div class="node-path">{record.nodeKey()}</div> |
||||
</div> |
</div> |
||||
</div> |
</div> |
||||
|
|
||||
<style> |
<style> |
||||
|
|
||||
|
</style> |
||||
|
|
||||
</style> |
|
||||
|
|||||
@ -1,82 +1,85 @@ |
|||||
<script> |
<script> |
||||
|
import HierarchyRow from "./HierarchyRow.svelte" |
||||
|
import RecordView from "./RecordView.svelte" |
||||
|
import IndexView from "./IndexView.svelte" |
||||
|
import ActionsHeader from "./ActionsHeader.svelte" |
||||
|
import { store } from "../builderStore" |
||||
|
import getIcon from "../common/icon" |
||||
|
import DropdownButton from "../common/DropdownButton.svelte" |
||||
|
import { hierarchy as hierarchyFunctions } from "../../../core/src" |
||||
|
|
||||
import HierarchyRow from "./HierarchyRow.svelte"; |
const hierarchyWidth = "200px" |
||||
import RecordView from "./RecordView.svelte"; |
|
||||
import IndexView from "./IndexView.svelte"; |
|
||||
import ActionsHeader from "./ActionsHeader.svelte"; |
|
||||
import {store} from "../builderStore"; |
|
||||
import getIcon from "../common/icon"; |
|
||||
import DropdownButton from "../common/DropdownButton.svelte"; |
|
||||
import {hierarchy as hierarchyFunctions} from "../../../core/src"; |
|
||||
|
|
||||
const hierarchyWidth = "200px"; |
const defaultNewIndexActions = [ |
||||
|
{ |
||||
|
label: "New Root Index", |
||||
|
onclick: store.newRootIndex, |
||||
|
}, |
||||
|
] |
||||
|
|
||||
const defaultNewIndexActions = [{ |
const defaultNewRecordActions = [ |
||||
label:"New Root Index", |
{ |
||||
onclick: store.newRootIndex |
label: "New Root Record", |
||||
}]; |
onclick: store.newRootRecord, |
||||
|
}, |
||||
|
] |
||||
|
|
||||
const defaultNewRecordActions = [{ |
let newIndexActions = defaultNewIndexActions |
||||
label:"New Root Record", |
let newRecordActions = defaultNewRecordActions |
||||
onclick: store.newRootRecord |
|
||||
}]; |
|
||||
|
|
||||
let newIndexActions = defaultNewIndexActions; |
store.subscribe(db => { |
||||
let newRecordActions = defaultNewRecordActions; |
if (!db.currentNode || hierarchyFunctions.isIndex(db.currentNode)) { |
||||
|
newRecordActions = defaultNewRecordActions |
||||
store.subscribe(db => { |
newIndexActions = defaultNewIndexActions |
||||
if(!db.currentNode || hierarchyFunctions.isIndex(db.currentNode)) { |
|
||||
newRecordActions = defaultNewRecordActions; |
|
||||
newIndexActions = defaultNewIndexActions; |
|
||||
} else { |
} else { |
||||
newRecordActions = [ |
newRecordActions = [ |
||||
...defaultNewRecordActions, |
...defaultNewRecordActions, |
||||
{label: `New Child Record of ${db.currentNode.name}`, |
{ |
||||
onclick: store.newChildRecord} |
label: `New Child Record of ${db.currentNode.name}`, |
||||
]; |
onclick: store.newChildRecord, |
||||
|
}, |
||||
|
] |
||||
|
|
||||
newIndexActions = [ |
newIndexActions = [ |
||||
...defaultNewIndexActions, |
...defaultNewIndexActions, |
||||
{label: `New Index on ${db.currentNode.name}`, |
{ |
||||
onclick: store.newChildIndex} |
label: `New Index on ${db.currentNode.name}`, |
||||
]; |
onclick: store.newChildIndex, |
||||
|
}, |
||||
|
] |
||||
} |
} |
||||
}); |
}) |
||||
|
|
||||
|
|
||||
</script> |
</script> |
||||
|
|
||||
<div class="root"> |
<div class="root"> |
||||
<div class="actions-header"> |
<div class="actions-header"> |
||||
{#if $store.currentNode} |
{#if $store.currentNode} |
||||
<ActionsHeader left={hierarchyWidth}/> |
<ActionsHeader left={hierarchyWidth} /> |
||||
{/if} |
{/if} |
||||
</div> |
</div> |
||||
<div class="node-view"> |
<div class="node-view"> |
||||
{#if !$store.currentNode} |
{#if !$store.currentNode} |
||||
<h1 style="margin-left: 100px">:)</h1> |
<h1 style="margin-left: 100px">:)</h1> |
||||
{:else if $store.currentNode.type === "record"} |
{:else if $store.currentNode.type === 'record'} |
||||
<RecordView /> |
<RecordView /> |
||||
{:else} |
{:else} |
||||
<IndexView /> |
<IndexView /> |
||||
{/if} |
{/if} |
||||
</div> |
</div> |
||||
</div> |
</div> |
||||
|
|
||||
|
|
||||
<style> |
<style> |
||||
.root { |
.root { |
||||
height: 100%; |
height: 100%; |
||||
position: relative; |
position: relative; |
||||
} |
} |
||||
|
|
||||
.actions-header { |
.actions-header { |
||||
flex: 0 1 auto; |
flex: 0 1 auto; |
||||
} |
} |
||||
|
|
||||
.node-view { |
.node-view { |
||||
overflow-y: auto; |
overflow-y: auto; |
||||
flex: 1 1 auto; |
flex: 1 1 auto; |
||||
} |
} |
||||
|
</style> |
||||
</style> |
|
||||
|
|||||
@ -1,121 +1,158 @@ |
|||||
<script> |
<script> |
||||
import Dropdown from "../common/Dropdown.svelte"; |
import Dropdown from "../common/Dropdown.svelte" |
||||
import Textbox from "../common/Textbox.svelte"; |
import Textbox from "../common/Textbox.svelte" |
||||
import Button from "../common/Button.svelte"; |
import Button from "../common/Button.svelte" |
||||
import ButtonGroup from "../common/ButtonGroup.svelte"; |
import ButtonGroup from "../common/ButtonGroup.svelte" |
||||
import NumberBox from "../common/NumberBox.svelte"; |
import NumberBox from "../common/NumberBox.svelte" |
||||
import ValuesList from "../common/ValuesList.svelte"; |
import ValuesList from "../common/ValuesList.svelte" |
||||
import ErrorsBox from "../common/ErrorsBox.svelte"; |
import ErrorsBox from "../common/ErrorsBox.svelte" |
||||
import Checkbox from "../common/Checkbox.svelte"; |
import Checkbox from "../common/Checkbox.svelte" |
||||
import DatePicker from "../common/DatePicker.svelte"; |
import DatePicker from "../common/DatePicker.svelte" |
||||
import {cloneDeep, assign, keys, |
import { |
||||
isNumber, includes, map, isBoolean} from "lodash/fp"; |
cloneDeep, |
||||
import {allTypes, validate, getPotentialReferenceIndexes, |
assign, |
||||
getDefaultTypeOptions, getNode, |
keys, |
||||
getPotentialReverseReferenceIndexes} from "../common/core"; |
isNumber, |
||||
|
includes, |
||||
export let field; |
map, |
||||
export let allFields; |
isBoolean, |
||||
export let onFinished = () => {}; |
} from "lodash/fp" |
||||
export let store; |
import { |
||||
|
allTypes, |
||||
let errors = []; |
validate, |
||||
let clonedField = cloneDeep(field); |
getPotentialReferenceIndexes, |
||||
|
getDefaultTypeOptions, |
||||
$: isNew = !!field && field.name.length === 0; |
getNode, |
||||
|
getPotentialReverseReferenceIndexes, |
||||
$: possibleReferenceIndexes = getPotentialReferenceIndexes( |
} from "../common/core" |
||||
store.hierarchy, store.currentNode |
|
||||
); |
export let field |
||||
|
export let allFields |
||||
$: selectedReverseRefIndex = |
export let onFinished = () => {} |
||||
!clonedField.typeOptions.indexNodeKey |
export let store |
||||
|
|
||||
|
let errors = [] |
||||
|
let clonedField = cloneDeep(field) |
||||
|
|
||||
|
$: isNew = !!field && field.name.length === 0 |
||||
|
|
||||
|
$: possibleReferenceIndexes = getPotentialReferenceIndexes( |
||||
|
store.hierarchy, |
||||
|
store.currentNode |
||||
|
) |
||||
|
|
||||
|
$: selectedReverseRefIndex = !clonedField.typeOptions.indexNodeKey |
||||
? "" |
? "" |
||||
: getNode(store.hierarchy, clonedField.typeOptions.indexNodeKey); |
: getNode(store.hierarchy, clonedField.typeOptions.indexNodeKey) |
||||
|
|
||||
$: possibleReverseReferenceIndexes = |
$: possibleReverseReferenceIndexes = !selectedReverseRefIndex |
||||
!selectedReverseRefIndex |
|
||||
? [] |
? [] |
||||
: getPotentialReverseReferenceIndexes( |
: getPotentialReverseReferenceIndexes( |
||||
store.hierarchy, selectedReverseRefIndex); |
store.hierarchy, |
||||
|
selectedReverseRefIndex |
||||
const typeChanged = (ev) => |
) |
||||
clonedField.typeOptions = getDefaultTypeOptions(ev.detail); |
|
||||
|
const typeChanged = ev => |
||||
|
(clonedField.typeOptions = getDefaultTypeOptions(ev.detail)) |
||||
const save = () => { |
|
||||
|
const save = () => { |
||||
errors = validate.field(allFields)(clonedField); |
errors = validate.field(allFields)(clonedField) |
||||
if(errors.length > 0) return; |
if (errors.length > 0) return |
||||
field.typeOptions = cloneDeep(clonedField.typeOptions); |
field.typeOptions = cloneDeep(clonedField.typeOptions) |
||||
onFinished( |
onFinished(assign(field)(clonedField)) |
||||
assign(field)(clonedField) |
} |
||||
); |
|
||||
} |
|
||||
|
|
||||
</script> |
</script> |
||||
|
|
||||
<div class="root"> |
<div class="root"> |
||||
|
|
||||
<ErrorsBox errors={errors} /> |
<ErrorsBox {errors} /> |
||||
|
|
||||
<form class="uk-form-horizontal"> |
<form class="uk-form-horizontal"> |
||||
|
|
||||
<Dropdown label="Type" bind:selected={clonedField.type} options={keys(allTypes)} on:change={typeChanged} /> |
<Dropdown |
||||
|
label="Type" |
||||
{#if isNew} |
bind:selected={clonedField.type} |
||||
<Textbox label="Field Name" bind:text={clonedField.name} /> |
options={keys(allTypes)} |
||||
{:else} |
on:change={typeChanged} /> |
||||
<div style="font-weight: bold">{clonedField.name}</div> |
|
||||
{/if} |
{#if isNew} |
||||
|
<Textbox label="Field Name" bind:text={clonedField.name} /> |
||||
<Textbox label="Label" bind:text={clonedField.label} /> |
{:else} |
||||
|
<div style="font-weight: bold">{clonedField.name}</div> |
||||
{#if clonedField.type === "string"} |
{/if} |
||||
<NumberBox label="Max Length" bind:value={clonedField.typeOptions.maxLength} /> |
|
||||
<ValuesList label="Values (options)" bind:values={clonedField.typeOptions.values} /> |
<Textbox label="Label" bind:text={clonedField.label} /> |
||||
<Checkbox label="Declared Values Only" bind:checked={clonedField.typeOptions.allowDeclaredValuesOnly} /> |
|
||||
{:else if clonedField.type === "bool"} |
{#if clonedField.type === 'string'} |
||||
<Checkbox label="Allow Null" bind:checked={clonedField.typeOptions.allowNulls} /> |
<NumberBox |
||||
{:else if clonedField.type === "datetime"} |
label="Max Length" |
||||
<DatePicker label="Min Value" bind:value={clonedField.typeOptions.minValue} /> |
bind:value={clonedField.typeOptions.maxLength} /> |
||||
<DatePicker label="Max Value" bind:value={clonedField.typeOptions.maxValue} /> |
<ValuesList |
||||
{:else if clonedField.type === "number"} |
label="Values (options)" |
||||
<NumberBox label="Min Value" bind:value={clonedField.typeOptions.minValue} /> |
bind:values={clonedField.typeOptions.values} /> |
||||
<NumberBox label="Max Value" bind:value={clonedField.typeOptions.maxValue} /> |
<Checkbox |
||||
<NumberBox label="Decimal Places" bind:value={clonedField.typeOptions.decimalPlaces} /> |
label="Declared Values Only" |
||||
{:else if clonedField.type === "reference"} |
bind:checked={clonedField.typeOptions.allowDeclaredValuesOnly} /> |
||||
<Dropdown label="Lookup Index" |
{:else if clonedField.type === 'bool'} |
||||
options={possibleReferenceIndexes} |
<Checkbox |
||||
valueMember={n => n.nodeKey()} |
label="Allow Null" |
||||
textMember={n => n.name} |
bind:checked={clonedField.typeOptions.allowNulls} /> |
||||
bind:selected={clonedField.typeOptions.indexNodeKey} /> |
{:else if clonedField.type === 'datetime'} |
||||
|
<DatePicker |
||||
<Dropdown label="Reverse Reference Index" |
label="Min Value" |
||||
options={possibleReverseReferenceIndexes} |
bind:value={clonedField.typeOptions.minValue} /> |
||||
multiple=true |
<DatePicker |
||||
valueMember={n => n.nodeKey()} |
label="Max Value" |
||||
textMember={n => n.name} |
bind:value={clonedField.typeOptions.maxValue} /> |
||||
bind:selected={clonedField.typeOptions.reverseIndexNodeKeys} /> |
{:else if clonedField.type === 'number'} |
||||
|
<NumberBox |
||||
<Textbox label="Display Value" bind:text={clonedField.typeOptions.displayValue} /> |
label="Min Value" |
||||
|
bind:value={clonedField.typeOptions.minValue} /> |
||||
{:else if clonedField.type.startsWith("array")} |
<NumberBox |
||||
<NumberBox label="Min Length" bind:value={clonedField.typeOptions.minLength} /> |
label="Max Value" |
||||
<NumberBox label="Max Length" bind:value={clonedField.typeOptions.maxLength} /> |
bind:value={clonedField.typeOptions.maxValue} /> |
||||
{/if} |
<NumberBox |
||||
|
label="Decimal Places" |
||||
</form> |
bind:value={clonedField.typeOptions.decimalPlaces} /> |
||||
|
{:else if clonedField.type === 'reference'} |
||||
<ButtonGroup style="float: right;"> |
<Dropdown |
||||
<Button color="primary" grouped on:click={save}>Save</Button> |
label="Lookup Index" |
||||
<Button color="tertiary" grouped on:click={() => onFinished(false)}>Cancel</Button> |
options={possibleReferenceIndexes} |
||||
</ButtonGroup> |
valueMember={n => n.nodeKey()} |
||||
|
textMember={n => n.name} |
||||
|
bind:selected={clonedField.typeOptions.indexNodeKey} /> |
||||
|
|
||||
|
<Dropdown |
||||
|
label="Reverse Reference Index" |
||||
|
options={possibleReverseReferenceIndexes} |
||||
|
multiple="true" |
||||
|
valueMember={n => n.nodeKey()} |
||||
|
textMember={n => n.name} |
||||
|
bind:selected={clonedField.typeOptions.reverseIndexNodeKeys} /> |
||||
|
|
||||
|
<Textbox |
||||
|
label="Display Value" |
||||
|
bind:text={clonedField.typeOptions.displayValue} /> |
||||
|
{:else if clonedField.type.startsWith('array')} |
||||
|
<NumberBox |
||||
|
label="Min Length" |
||||
|
bind:value={clonedField.typeOptions.minLength} /> |
||||
|
<NumberBox |
||||
|
label="Max Length" |
||||
|
bind:value={clonedField.typeOptions.maxLength} /> |
||||
|
{/if} |
||||
|
|
||||
|
</form> |
||||
|
|
||||
|
<ButtonGroup style="float: right;"> |
||||
|
<Button color="primary" grouped on:click={save}>Save</Button> |
||||
|
<Button color="tertiary" grouped on:click={() => onFinished(false)}> |
||||
|
Cancel |
||||
|
</Button> |
||||
|
</ButtonGroup> |
||||
|
|
||||
</div> |
</div> |
||||
|
|
||||
<style> |
<style> |
||||
|
|
||||
|
</style> |
||||
|
|
||||
</style> |
|
||||
|
|||||
@ -1,45 +1,42 @@ |
|||||
<script> |
<script> |
||||
|
import { store } from "../builderStore" |
||||
import {store} from "../builderStore"; |
import { cloneDeep } from "lodash/fp" |
||||
import {cloneDeep} from "lodash/fp"; |
export let level = 0 |
||||
export let level = 0; |
export let node |
||||
export let node; |
|
||||
|
|
||||
</script> |
</script> |
||||
|
|
||||
<div class="root"> |
<div class="root"> |
||||
<div class="title" on:click={() => store.selectExistingNode(node.nodeId)} style="padding-left: {20 + (level * 20)}px"> |
<div |
||||
{node.name} |
class="title" |
||||
</div> |
on:click={() => store.selectExistingNode(node.nodeId)} |
||||
{#if node.children} |
style="padding-left: {20 + level * 20}px"> |
||||
|
{node.name} |
||||
|
</div> |
||||
|
{#if node.children} |
||||
{#each node.children as child} |
{#each node.children as child} |
||||
<svelte:self node={child} |
<svelte:self node={child} level={level + 1} /> |
||||
level={level+1}/> |
|
||||
{/each} |
{/each} |
||||
{/if} |
{/if} |
||||
</div> |
</div> |
||||
|
|
||||
|
|
||||
<style> |
<style> |
||||
|
.root { |
||||
.root { |
|
||||
display: block; |
display: block; |
||||
font-size: .9rem; |
font-size: 0.9rem; |
||||
width: 100%; |
width: 100%; |
||||
cursor: pointer; |
cursor: pointer; |
||||
font-weight: bold; |
font-weight: bold; |
||||
} |
} |
||||
|
|
||||
.title { |
.title { |
||||
font: var(--fontblack); |
font: var(--fontblack); |
||||
padding-top: 10px; |
padding-top: 10px; |
||||
padding-right: 5px; |
padding-right: 5px; |
||||
padding-bottom: 10px; |
padding-bottom: 10px; |
||||
color: var(--secondary100); |
color: var(--secondary100); |
||||
} |
} |
||||
|
|
||||
.title:hover { |
.title:hover { |
||||
background-color: var(--secondary10); |
background-color: var(--secondary10); |
||||
} |
} |
||||
|
</style> |
||||
</style> |
|
||||
|
|||||
@ -1,76 +1,79 @@ |
|||||
<script> |
<script> |
||||
|
import Textbox from "../common/Textbox.svelte" |
||||
import Textbox from "../common/Textbox.svelte"; |
import CodeArea from "../common/CodeArea.svelte" |
||||
import CodeArea from "../common/CodeArea.svelte"; |
import Button from "../common/Button.svelte" |
||||
import Button from "../common/Button.svelte"; |
import Dropdown from "../common/Dropdown.svelte" |
||||
import Dropdown from "../common/Dropdown.svelte"; |
import { store } from "../builderStore" |
||||
import {store} from "../builderStore"; |
import { filter, some, map } from "lodash/fp" |
||||
import {filter, some, map} from "lodash/fp"; |
import { hierarchy as hierarchyFunctions, common } from "../../../core/src" |
||||
import {hierarchy as hierarchyFunctions, common} from "../../../core/src"; |
|
||||
|
const pipe = common.$ |
||||
const pipe = common.$; |
|
||||
|
let index |
||||
let index; |
let indexableRecords = [] |
||||
let indexableRecords = []; |
|
||||
|
store.subscribe($store => { |
||||
store.subscribe($store => { |
index = $store.currentNode |
||||
index = $store.currentNode; |
indexableRecords = pipe($store.hierarchy, [ |
||||
indexableRecords = pipe($store.hierarchy,[ |
hierarchyFunctions.getFlattenedHierarchy, |
||||
hierarchyFunctions.getFlattenedHierarchy, |
filter(hierarchyFunctions.isDecendant(index.parent())), |
||||
filter(hierarchyFunctions.isDecendant(index.parent())), |
filter(hierarchyFunctions.isRecord), |
||||
filter(hierarchyFunctions.isRecord), |
map(n => ({ |
||||
map(n => ({ |
node: n, |
||||
node:n, |
isallowed: some(id => n.nodeId === id)(index.allowedRecordNodeIds), |
||||
isallowed: some(id => n.nodeId === id)(index.allowedRecordNodeIds) |
})), |
||||
})) |
]) |
||||
]); |
}) |
||||
}); |
|
||||
|
const toggleAllowedRecord = record => { |
||||
const toggleAllowedRecord = record => { |
if (record.isallowed) { |
||||
if(record.isallowed) { |
index.allowedRecordNodeIds = filter(id => id !== record.node.nodeId)( |
||||
index.allowedRecordNodeIds = filter(id => id !== record.node.nodeId) |
index.allowedRecordNodeIds |
||||
(index.allowedRecordNodeIds); |
) |
||||
} else { |
} else { |
||||
index.allowedRecordNodeIds.push(record.node.nodeId); |
index.allowedRecordNodeIds.push(record.node.nodeId) |
||||
} |
} |
||||
}; |
} |
||||
|
|
||||
</script> |
</script> |
||||
|
|
||||
<form class="uk-form-horizontal root"> |
<form class="uk-form-horizontal root"> |
||||
<Textbox bind:text={index.name} label="Name"/> |
<Textbox bind:text={index.name} label="Name" /> |
||||
|
|
||||
<div class="allowed-records"> |
<div class="allowed-records"> |
||||
<div>Records to Index</div> |
<div>Records to Index</div> |
||||
{#each indexableRecords as rec} |
{#each indexableRecords as rec} |
||||
<input type="checkbox" checked={rec.isallowed} on:change={() => toggleAllowedRecord(rec)}/> |
<input |
||||
<span>{rec.node.name}</span> |
type="checkbox" |
||||
{/each} |
checked={rec.isallowed} |
||||
</div> |
on:change={() => toggleAllowedRecord(rec)} /> |
||||
|
<span>{rec.node.name}</span> |
||||
|
{/each} |
||||
|
</div> |
||||
|
|
||||
|
<Dropdown |
||||
|
label="Index Type" |
||||
|
bind:selected={index.indexType} |
||||
|
options={['ancestor', 'reference']} /> |
||||
|
|
||||
|
<CodeArea bind:text={index.map} label="Map (javascript)" /> |
||||
|
<CodeArea bind:text={index.filter} label="Filter (javascript expression)" /> |
||||
|
<CodeArea |
||||
|
bind:text={index.getShardName} |
||||
|
label="Shard Name (javascript expression)" /> |
||||
|
|
||||
|
|
||||
<Dropdown label="Index Type" bind:selected={index.indexType} options={["ancestor", "reference"]} /> |
|
||||
|
|
||||
<CodeArea bind:text={index.map} label="Map (javascript)"/> |
|
||||
<CodeArea bind:text={index.filter} label="Filter (javascript expression)"/> |
|
||||
<CodeArea bind:text={index.getShardName} label="Shard Name (javascript expression)"/> |
|
||||
|
|
||||
|
|
||||
</form> |
</form> |
||||
|
|
||||
<style> |
<style> |
||||
|
.root { |
||||
.root { |
|
||||
height: 100%; |
height: 100%; |
||||
padding: 15px; |
padding: 15px; |
||||
} |
} |
||||
|
|
||||
.allowed-records { |
.allowed-records { |
||||
margin: 20px 0px; |
margin: 20px 0px; |
||||
} |
} |
||||
|
|
||||
.allowed-records > span { |
|
||||
margin-right:30px; |
|
||||
} |
|
||||
|
|
||||
</style> |
.allowed-records > span { |
||||
|
margin-right: 30px; |
||||
|
} |
||||
|
</style> |
||||
|
|||||
@ -1,300 +1,307 @@ |
|||||
<script> |
<script> |
||||
|
import Textbox from "../common/Textbox.svelte" |
||||
import Textbox from "../common/Textbox.svelte"; |
import Button from "../common/Button.svelte" |
||||
import Button from "../common/Button.svelte"; |
import getIcon from "../common/icon" |
||||
import getIcon from "../common/icon"; |
import FieldView from "./FieldView.svelte" |
||||
import FieldView from "./FieldView.svelte"; |
import Modal from "../common/Modal.svelte" |
||||
import Modal from "../common/Modal.svelte"; |
import { map, join, filter, some, find, keys, isDate } from "lodash/fp" |
||||
import {map, join, filter, some, |
import { store } from "../builderStore" |
||||
find, keys, isDate} from "lodash/fp"; |
import { common, hierarchy as h } from "../../../core/src" |
||||
import { store } from "../builderStore"; |
import { templateApi, pipe, validate } from "../common/core" |
||||
import {common, hierarchy as h} from "../../../core/src"; |
|
||||
import {templateApi, pipe, validate} from "../common/core"; |
let record |
||||
|
let getIndexAllowedRecords |
||||
let record; |
let editingField = false |
||||
let getIndexAllowedRecords; |
let fieldToEdit |
||||
let editingField = false; |
let isNewField = false |
||||
let fieldToEdit; |
let newField |
||||
let isNewField = false; |
let editField |
||||
let newField; |
let deleteField |
||||
let editField; |
let onFinishedFieldEdit |
||||
let deleteField; |
let editIndex |
||||
let onFinishedFieldEdit; |
|
||||
let editIndex; |
store.subscribe($store => { |
||||
|
record = $store.currentNode |
||||
store.subscribe($store => { |
const flattened = h.getFlattenedHierarchy($store.hierarchy) |
||||
record = $store.currentNode; |
getIndexAllowedRecords = index => |
||||
const flattened = h.getFlattenedHierarchy($store.hierarchy); |
pipe(index.allowedRecordNodeIds, [ |
||||
getIndexAllowedRecords = index => |
filter(id => some(n => n.nodeId === id)(flattened)), |
||||
pipe(index.allowedRecordNodeIds, [ |
map(id => find(n => n.nodeId === id)(flattened).name), |
||||
filter(id => some(n => n.nodeId === id)(flattened)), |
join(", "), |
||||
map(id => find(n => n.nodeId === id) |
]) |
||||
(flattened).name), |
|
||||
join(", ") |
|
||||
]); |
|
||||
|
|
||||
newField = () => { |
newField = () => { |
||||
isNewField = true; |
isNewField = true |
||||
fieldToEdit = templateApi($store.hierarchy).getNewField("string"); |
fieldToEdit = templateApi($store.hierarchy).getNewField("string") |
||||
editingField = true; |
editingField = true |
||||
} |
} |
||||
|
|
||||
|
onFinishedFieldEdit = field => { |
||||
onFinishedFieldEdit = (field) => { |
if (field) { |
||||
if(field) { |
store.saveField(field) |
||||
store.saveField(field); |
} |
||||
} |
editingField = false |
||||
editingField = false; |
|
||||
} |
} |
||||
|
|
||||
editField = (field) => { |
editField = field => { |
||||
isNewField = false; |
isNewField = false |
||||
fieldToEdit = field; |
fieldToEdit = field |
||||
editingField = true; |
editingField = true |
||||
} |
} |
||||
|
|
||||
deleteField = (field) => { |
deleteField = field => { |
||||
store.deleteField(field); |
store.deleteField(field) |
||||
} |
} |
||||
|
|
||||
editIndex = index => { |
editIndex = index => { |
||||
store.selectExistingNode(index.nodeId); |
store.selectExistingNode(index.nodeId) |
||||
} |
} |
||||
|
}) |
||||
}) |
|
||||
|
let getTypeOptionsValueText = value => { |
||||
let getTypeOptionsValueText = value => { |
if ( |
||||
if(value === Number.MAX_SAFE_INTEGER |
value === Number.MAX_SAFE_INTEGER || |
||||
|| value === Number.MIN_SAFE_INTEGER |
value === Number.MIN_SAFE_INTEGER || |
||||
|| new Date(value).getTime() === new Date(8640000000000000).getTime() |
new Date(value).getTime() === new Date(8640000000000000).getTime() || |
||||
|| new Date(value).getTime() === new Date(-8640000000000000).getTime()) return "(any)"; |
new Date(value).getTime() === new Date(-8640000000000000).getTime() |
||||
|
) |
||||
if(value === null) return "(not set)"; |
return "(any)" |
||||
return value; |
|
||||
} |
if (value === null) return "(not set)" |
||||
|
return value |
||||
let getTypeOptions = typeOptions => |
} |
||||
|
|
||||
|
let getTypeOptions = typeOptions => |
||||
pipe(typeOptions, [ |
pipe(typeOptions, [ |
||||
keys, |
keys, |
||||
map(k => `<span style="color:var(--slate)">${k}: </span>${getTypeOptionsValueText(typeOptions[k])}`), |
map( |
||||
join("<br>") |
k => |
||||
]); |
`<span style="color:var(--slate)">${k}: </span>${getTypeOptionsValueText( |
||||
|
typeOptions[k] |
||||
const nameChanged = ev => { |
)}` |
||||
const pluralName = n => `${n}s`; |
), |
||||
if(record.collectionName === "") { |
join("<br>"), |
||||
record.collectionName = pluralName(ev.target.value); |
]) |
||||
|
|
||||
|
const nameChanged = ev => { |
||||
|
const pluralName = n => `${n}s` |
||||
|
if (record.collectionName === "") { |
||||
|
record.collectionName = pluralName(ev.target.value) |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
</script> |
</script> |
||||
|
|
||||
<div class="root"> |
<div class="root"> |
||||
|
|
||||
<form class="uk-form-horizontal"> |
<form class="uk-form-horizontal"> |
||||
<h3 class="settings-title"> |
<h3 class="settings-title">Settings</h3> |
||||
Settings |
|
||||
</h3> |
<Textbox label="Name:" bind:text={record.name} on:change={nameChanged} /> |
||||
|
{#if !record.isSingle} |
||||
<Textbox label="Name:" bind:text={record.name} on:change={nameChanged}/> |
<Textbox label="Collection Name:" bind:text={record.collectionName} /> |
||||
{#if !record.isSingle} |
<Textbox label="Shard Factor:" bind:text={record.allidsShardFactor} /> |
||||
<Textbox label="Collection Name:" bind:text={record.collectionName} /> |
|
||||
<Textbox label="Shard Factor:" bind:text={record.allidsShardFactor} /> |
|
||||
{/if} |
|
||||
<div class="recordkey">{record.nodeKey()}</div> |
|
||||
|
|
||||
</form> |
|
||||
<h3 class="title"> |
|
||||
Fields <span class="add-field-button" on:click={newField}>{@html getIcon("plus")}</span> |
|
||||
</h3> |
|
||||
|
|
||||
{#if record.fields.length > 0} |
|
||||
<table class="fields-table uk-table"> |
|
||||
<thead> |
|
||||
<tr> |
|
||||
<th>Name</th> |
|
||||
<th>Type</th> |
|
||||
<th>Options</th> |
|
||||
<th></th> |
|
||||
</tr> |
|
||||
</thead> |
|
||||
<tbody> |
|
||||
{#each record.fields as field} |
|
||||
<tr> |
|
||||
<td > |
|
||||
<div class="field-label">{field.label}</div> |
|
||||
<div style="font-size: 0.8em; color: var(--slate)">{field.name}</div> |
|
||||
</td> |
|
||||
<td >{field.type}</td> |
|
||||
<td >{@html getTypeOptions(field.typeOptions)}</td> |
|
||||
<td> |
|
||||
<span class="edit-button" on:click={() => editField(field)}>{@html getIcon("edit")}</span> |
|
||||
<span class="edit-button" on:click={() => deleteField(field)}>{@html getIcon("trash")}</span> |
|
||||
</td> |
|
||||
</tr> |
|
||||
{/each} |
|
||||
</tbody> |
|
||||
</table> |
|
||||
{:else} |
|
||||
(no fields added) |
|
||||
{/if} |
{/if} |
||||
|
<div class="recordkey">{record.nodeKey()}</div> |
||||
|
|
||||
|
</form> |
||||
|
<h3 class="title"> |
||||
|
Fields |
||||
|
<span class="add-field-button" on:click={newField}> |
||||
|
{@html getIcon('plus')} |
||||
|
</span> |
||||
|
</h3> |
||||
|
|
||||
{#if editingField} |
{#if record.fields.length > 0} |
||||
<Modal bind:isOpen={editingField} onClosed={() => onFinishedFieldEdit(false) }> |
<table class="fields-table uk-table"> |
||||
<FieldView field={fieldToEdit} |
<thead> |
||||
onFinished={onFinishedFieldEdit} |
<tr> |
||||
allFields={record.fields} |
<th>Name</th> |
||||
store={$store}/> |
<th>Type</th> |
||||
|
<th>Options</th> |
||||
|
<th /> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
{#each record.fields as field} |
||||
|
<tr> |
||||
|
<td> |
||||
|
<div class="field-label">{field.label}</div> |
||||
|
<div style="font-size: 0.8em; color: var(--slate)"> |
||||
|
{field.name} |
||||
|
</div> |
||||
|
</td> |
||||
|
<td>{field.type}</td> |
||||
|
<td> |
||||
|
{@html getTypeOptions(field.typeOptions)} |
||||
|
</td> |
||||
|
<td> |
||||
|
<span class="edit-button" on:click={() => editField(field)}> |
||||
|
{@html getIcon('edit')} |
||||
|
</span> |
||||
|
<span class="edit-button" on:click={() => deleteField(field)}> |
||||
|
{@html getIcon('trash')} |
||||
|
</span> |
||||
|
</td> |
||||
|
</tr> |
||||
|
{/each} |
||||
|
</tbody> |
||||
|
</table> |
||||
|
{:else}(no fields added){/if} |
||||
|
|
||||
|
{#if editingField} |
||||
|
<Modal |
||||
|
bind:isOpen={editingField} |
||||
|
onClosed={() => onFinishedFieldEdit(false)}> |
||||
|
<FieldView |
||||
|
field={fieldToEdit} |
||||
|
onFinished={onFinishedFieldEdit} |
||||
|
allFields={record.fields} |
||||
|
store={$store} /> |
||||
</Modal> |
</Modal> |
||||
{/if} |
{/if} |
||||
|
|
||||
<h3 class="title"> |
<h3 class="title">Indexes</h3> |
||||
Indexes |
|
||||
</h3> |
|
||||
|
|
||||
{#each record.indexes as index} |
{#each record.indexes as index} |
||||
<div class="index-container"> |
<div class="index-container"> |
||||
<div class="index-name"> |
<div class="index-name"> |
||||
{index.name} |
{index.name} |
||||
<span style="margin-left: 7px" on:click={() => editIndex(index)}>{@html getIcon("edit")}</span> |
<span style="margin-left: 7px" on:click={() => editIndex(index)}> |
||||
</div> |
{@html getIcon('edit')} |
||||
<div class="index-field-row"> |
</span> |
||||
<span class="index-label">records indexed: </span> |
</div> |
||||
<span>{getIndexAllowedRecords(index)}</span> |
<div class="index-field-row"> |
||||
<span class="index-label" style="margin-left: 15px">type:</span> |
<span class="index-label">records indexed:</span> |
||||
<span>{index.indexType}</span> |
<span>{getIndexAllowedRecords(index)}</span> |
||||
</div> |
<span class="index-label" style="margin-left: 15px">type:</span> |
||||
|
<span>{index.indexType}</span> |
||||
|
</div> |
||||
|
<div class="index-field-row"> |
||||
|
<span class="index-label">map:</span> |
||||
|
<code class="index-mapfilter">{index.map}</code> |
||||
|
</div> |
||||
|
{#if index.filter} |
||||
<div class="index-field-row"> |
<div class="index-field-row"> |
||||
<span class="index-label">map:</span> |
<span class="index-label">filter:</span> |
||||
<code class="index-mapfilter">{index.map}</code> |
<code class="index-mapfilter">{index.filter}</code> |
||||
</div> |
</div> |
||||
{#if index.filter} |
{/if} |
||||
<div class="index-field-row"> |
|
||||
<span class="index-label">filter:</span> |
|
||||
<code class="index-mapfilter">{index.filter}</code> |
|
||||
</div> |
|
||||
{/if} |
|
||||
</div> |
|
||||
{:else} |
|
||||
<div class="no-indexes"> |
|
||||
No indexes added. |
|
||||
</div> |
</div> |
||||
{/each} |
{:else} |
||||
|
<div class="no-indexes">No indexes added.</div> |
||||
|
{/each} |
||||
|
|
||||
</div> |
</div> |
||||
|
|
||||
|
|
||||
<style> |
<style> |
||||
|
.root { |
||||
.root { |
|
||||
height: 100%; |
height: 100%; |
||||
padding: 2rem; |
padding: 2rem; |
||||
} |
} |
||||
|
|
||||
.settings-title { |
.settings-title { |
||||
font-weight: 700; |
font-weight: 700; |
||||
} |
} |
||||
|
|
||||
.title { |
.title { |
||||
margin: 3rem 0rem 0rem 0rem; |
margin: 3rem 0rem 0rem 0rem; |
||||
font-weight: 700; |
font-weight: 700; |
||||
} |
} |
||||
|
|
||||
.recordkey { |
.recordkey { |
||||
font-size: 14px; |
font-size: 14px; |
||||
font-weight: 600; |
font-weight: 600; |
||||
color: var(--primary100); |
color: var(--primary100); |
||||
} |
} |
||||
|
|
||||
.fields-table { |
.fields-table { |
||||
margin: 1rem 1rem 0rem 0rem; |
margin: 1rem 1rem 0rem 0rem; |
||||
border-collapse:collapse; |
border-collapse: collapse; |
||||
} |
} |
||||
|
|
||||
.add-field-button { |
.add-field-button { |
||||
cursor:pointer; |
cursor: pointer; |
||||
} |
} |
||||
|
|
||||
.edit-button { |
.edit-button { |
||||
cursor:pointer; |
cursor: pointer; |
||||
color: var(--secondary25); |
color: var(--secondary25); |
||||
} |
} |
||||
|
|
||||
.edit-button:hover { |
.edit-button:hover { |
||||
cursor:pointer; |
cursor: pointer; |
||||
color: var(--secondary75); |
color: var(--secondary75); |
||||
} |
} |
||||
|
|
||||
th { |
th { |
||||
text-align: left; |
text-align: left; |
||||
} |
} |
||||
|
|
||||
td { |
td { |
||||
padding: 1rem 5rem 1rem 0rem; |
padding: 1rem 5rem 1rem 0rem; |
||||
margin:0; |
margin: 0; |
||||
font-size: 14px; |
font-size: 14px; |
||||
font-weight: 500; |
font-weight: 500; |
||||
|
} |
||||
|
|
||||
} |
.field-label { |
||||
|
font-size: 14px; |
||||
.field-label { |
font-weight: 500; |
||||
font-size: 14px; |
} |
||||
font-weight: 500; |
|
||||
} |
|
||||
|
|
||||
thead > tr { |
thead > tr { |
||||
border-width: 0px 0px 1px 0px; |
border-width: 0px 0px 1px 0px; |
||||
border-style: solid; |
border-style: solid; |
||||
border-color: var(--secondary75); |
border-color: var(--secondary75); |
||||
margin-bottom: 20px; |
margin-bottom: 20px; |
||||
} |
} |
||||
|
|
||||
tbody > tr { |
tbody > tr { |
||||
border-width: 0px 0px 1px 0px; |
border-width: 0px 0px 1px 0px; |
||||
border-style: solid; |
border-style: solid; |
||||
border-color: var(--primary10); |
border-color: var(--primary10); |
||||
} |
} |
||||
|
|
||||
tbody > tr:hover { |
tbody > tr:hover { |
||||
background-color: var(--primary10); |
background-color: var(--primary10); |
||||
} |
} |
||||
|
|
||||
tbody > tr:hover .edit-button { |
tbody > tr:hover .edit-button { |
||||
color: var(--secondary75); |
color: var(--secondary75); |
||||
} |
} |
||||
|
|
||||
.index-container { |
.index-container { |
||||
border-style: solid; |
border-style: solid; |
||||
border-width: 0 0 1px 0; |
border-width: 0 0 1px 0; |
||||
border-color: var(--secondary25); |
border-color: var(--secondary25); |
||||
padding: 10px; |
padding: 10px; |
||||
margin-bottom: 5px; |
margin-bottom: 5px; |
||||
} |
} |
||||
|
|
||||
.index-label { |
.index-label { |
||||
color: var(--slate); |
color: var(--slate); |
||||
} |
} |
||||
|
|
||||
.index-name { |
.index-name { |
||||
font-weight: bold; |
font-weight: bold; |
||||
color: var(--primary100); |
color: var(--primary100); |
||||
} |
} |
||||
|
|
||||
.index-container code { |
.index-container code { |
||||
margin: 0; |
margin: 0; |
||||
display: inline; |
display: inline; |
||||
background-color: var(--primary10); |
background-color: var(--primary10); |
||||
color: var(--secondary100); |
color: var(--secondary100); |
||||
padding:3px; |
padding: 3px; |
||||
} |
} |
||||
|
|
||||
.index-field-row { |
.index-field-row { |
||||
margin: 1rem 0rem 0rem 0rem; |
margin: 1rem 0rem 0rem 0rem; |
||||
} |
} |
||||
|
|
||||
.no-indexes { |
.no-indexes { |
||||
margin: 1rem 0rem 0rem 0rem; |
margin: 1rem 0rem 0rem 0rem; |
||||
font-family: var(--fontnormal); |
font-family: var(--fontnormal); |
||||
font-size: 14px; |
font-size: 14px; |
||||
} |
} |
||||
</style> |
</style> |
||||
|
|||||
@ -1,163 +1,153 @@ |
|||||
<script> |
<script> |
||||
|
import { store } from "../builderStore" |
||||
import { store } from "../builderStore"; |
import HierarchyRow from "./HierarchyRow.svelte" |
||||
import HierarchyRow from "./HierarchyRow.svelte"; |
import DropdownButton from "../common/DropdownButton.svelte" |
||||
import DropdownButton from "../common/DropdownButton.svelte"; |
import { hierarchy as hierarchyFunctions } from "../../../core/src" |
||||
import {hierarchy as hierarchyFunctions} from "../../../core/src"; |
import NavItem from "./NavItem.svelte" |
||||
import NavItem from "./NavItem.svelte"; |
import getIcon from "../common/icon" |
||||
import getIcon from "../common/icon"; |
|
||||
|
const newRootRecord = () => { |
||||
|
store.newRootRecord() |
||||
const newRootRecord = () => { |
} |
||||
store.newRootRecord(); |
|
||||
} |
const newRootIndex = () => { |
||||
|
store.newRootIndex() |
||||
const newRootIndex = () => { |
} |
||||
store.newRootIndex(); |
|
||||
} |
const newChildRecord = () => { |
||||
|
store.newChildRecord() |
||||
const newChildRecord = () => { |
} |
||||
store.newChildRecord(); |
|
||||
} |
const newChildIndex = () => { |
||||
|
store.newChildIndex() |
||||
const newChildIndex = () => { |
} |
||||
store.newChildIndex(); |
|
||||
} |
const defaultNewChildActions = [ |
||||
|
|
||||
const defaultNewChildActions = [ |
|
||||
{ |
{ |
||||
label:"New Root Record", |
label: "New Root Record", |
||||
onclick: newRootRecord |
onclick: newRootRecord, |
||||
}, |
}, |
||||
{ |
{ |
||||
label:"New Root Index", |
label: "New Root Index", |
||||
onclick: newRootIndex |
onclick: newRootIndex, |
||||
} |
}, |
||||
]; |
] |
||||
|
|
||||
let newChildActions = defaultNewChildActions; |
let newChildActions = defaultNewChildActions |
||||
|
|
||||
const setActiveNav = (name) => () => { |
const setActiveNav = name => () => { |
||||
store.setActiveNav(name); |
store.setActiveNav(name) |
||||
} |
} |
||||
|
|
||||
store.subscribe(db => { |
store.subscribe(db => { |
||||
if(!db.currentNode || hierarchyFunctions.isIndex(db.currentNode)) { |
if (!db.currentNode || hierarchyFunctions.isIndex(db.currentNode)) { |
||||
newChildActions = defaultNewChildActions; |
newChildActions = defaultNewChildActions |
||||
} else { |
} else { |
||||
newChildActions = [ |
newChildActions = [ |
||||
{ |
{ |
||||
label:"New Root Record", |
label: "New Root Record", |
||||
onclick: newRootRecord |
onclick: newRootRecord, |
||||
}, |
}, |
||||
{ |
{ |
||||
label:"New Root Index", |
label: "New Root Index", |
||||
onclick: newRootIndex |
onclick: newRootIndex, |
||||
}, |
}, |
||||
{ |
{ |
||||
label: `New Child Record of ${db.currentNode.name}`, |
label: `New Child Record of ${db.currentNode.name}`, |
||||
onclick: newChildRecord |
onclick: newChildRecord, |
||||
}, |
}, |
||||
{ |
{ |
||||
label: `New Index on ${db.currentNode.name}`, |
label: `New Index on ${db.currentNode.name}`, |
||||
onclick: newChildIndex |
onclick: newChildIndex, |
||||
} |
}, |
||||
]; |
] |
||||
} |
} |
||||
}); |
}) |
||||
|
|
||||
</script> |
</script> |
||||
|
|
||||
|
|
||||
<div class="items-root"> |
<div class="items-root"> |
||||
<div class="hierarchy"> |
<div class="hierarchy"> |
||||
<div class="components-list-container"> |
<div class="components-list-container"> |
||||
<div class="nav-group-header"> |
<div class="nav-group-header"> |
||||
<div>{@html getIcon("database","18")}</div> |
<div> |
||||
<div class="hierarchy-title">Database</div> |
{@html getIcon('database', '18')} |
||||
<DropdownButton iconName="plus" actions={newChildActions} /> |
|
||||
</div> |
|
||||
</div> |
</div> |
||||
|
<div class="hierarchy-title">Database</div> |
||||
|
<DropdownButton iconName="plus" actions={newChildActions} /> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
<div class="hierarchy-items-container"> |
<div class="hierarchy-items-container"> |
||||
{#each $store.hierarchy.children as record} |
{#each $store.hierarchy.children as record} |
||||
<HierarchyRow node={record} |
<HierarchyRow node={record} type="record" /> |
||||
type="record" /> |
{/each} |
||||
{/each} |
|
||||
|
|
||||
{#each $store.hierarchy.indexes as index} |
{#each $store.hierarchy.indexes as index} |
||||
<HierarchyRow node={index} |
<HierarchyRow node={index} type="index" /> |
||||
type="index" /> |
{/each} |
||||
{/each} |
|
||||
</div> |
|
||||
</div> |
</div> |
||||
|
</div> |
||||
|
|
||||
<NavItem name="actions" label="Actions & Triggers"/> |
<NavItem name="actions" label="Actions & Triggers" /> |
||||
<NavItem name="access levels" label="User Levels"/> |
<NavItem name="access levels" label="User Levels" /> |
||||
|
|
||||
</div> |
</div> |
||||
|
|
||||
|
|
||||
<style> |
<style> |
||||
|
.items-root { |
||||
|
|
||||
.items-root { |
|
||||
display: flex; |
display: flex; |
||||
flex-direction: column; |
flex-direction: column; |
||||
max-height: 100%; |
max-height: 100%; |
||||
height: 100%; |
height: 100%; |
||||
background-color: var(--secondary5); |
background-color: var(--secondary5); |
||||
} |
} |
||||
|
|
||||
.nav-group-header { |
.nav-group-header { |
||||
display:grid; |
display: grid; |
||||
grid-template-columns: [icon] auto [title] 1fr [button] auto; |
grid-template-columns: [icon] auto [title] 1fr [button] auto; |
||||
padding: 2rem 1rem 0rem 1rem; |
padding: 2rem 1rem 0rem 1rem; |
||||
font-size: .9rem; |
font-size: 0.9rem; |
||||
font-weight: bold; |
font-weight: bold; |
||||
} |
} |
||||
|
|
||||
.nav-group-header>div:nth-child(1) { |
.nav-group-header > div:nth-child(1) { |
||||
padding: 0rem .7rem 0rem 0rem; |
padding: 0rem 0.7rem 0rem 0rem; |
||||
vertical-align: bottom; |
vertical-align: bottom; |
||||
grid-column-start: icon; |
grid-column-start: icon; |
||||
margin-right: 5px; |
margin-right: 5px; |
||||
} |
} |
||||
|
|
||||
.nav-group-header>div:nth-child(2) { |
.nav-group-header > div:nth-child(2) { |
||||
margin-left:5px; |
margin-left: 5px; |
||||
vertical-align: bottom; |
vertical-align: bottom; |
||||
grid-column-start: title; |
grid-column-start: title; |
||||
margin-top:auto; |
margin-top: auto; |
||||
} |
} |
||||
|
|
||||
.nav-group-header>div:nth-child(3) { |
.nav-group-header > div:nth-child(3) { |
||||
vertical-align: bottom; |
vertical-align: bottom; |
||||
grid-column-start: button; |
grid-column-start: button; |
||||
cursor: pointer; |
cursor: pointer; |
||||
color: var(--primary75); |
color: var(--primary75); |
||||
} |
} |
||||
|
|
||||
.nav-group-header>div:nth-child(3):hover { |
.nav-group-header > div:nth-child(3):hover { |
||||
color: var(--primary75); |
color: var(--primary75); |
||||
} |
} |
||||
|
|
||||
.hierarchy-title { |
.hierarchy-title { |
||||
flex: auto 1 1; |
flex: auto 1 1; |
||||
} |
} |
||||
|
|
||||
|
|
||||
.hierarchy { |
.hierarchy { |
||||
display:flex; |
display: flex; |
||||
flex-direction: column; |
flex-direction: column; |
||||
flex: 1 0 auto; |
flex: 1 0 auto; |
||||
height: 100px; |
height: 100px; |
||||
} |
} |
||||
|
|
||||
.hierarchy-items-container { |
.hierarchy-items-container { |
||||
flex: 1 1 auto; |
flex: 1 1 auto; |
||||
overflow-y:auto; |
overflow-y: auto; |
||||
} |
} |
||||
|
</style> |
||||
|
|
||||
</style> |
|
||||
|
|||||
@ -1,66 +1,63 @@ |
|||||
<script> |
<script> |
||||
|
import { store } from "../builderStore" |
||||
import {store} from "../builderStore"; |
import { cloneDeep } from "lodash/fp" |
||||
import {cloneDeep} from "lodash/fp"; |
import getIcon from "../common/icon" |
||||
import getIcon from "../common/icon"; |
export let level = 0 |
||||
export let level = 0; |
export let node |
||||
export let node; |
export let type |
||||
export let type; |
|
||||
|
let navActive = "" |
||||
let navActive = ""; |
$: icon = type === "index" ? "list" : "file" |
||||
$:icon = type==="index" ? "list" : "file"; |
|
||||
|
store.subscribe(s => { |
||||
store.subscribe(s => { |
if (s.currentNode) |
||||
if(s.currentNode) |
navActive = |
||||
navActive = (s.activeNav === "database" && node.nodeId === s.currentNode.nodeId |
s.activeNav === "database" && node.nodeId === s.currentNode.nodeId |
||||
? "active" : "") |
? "active" |
||||
}); |
: "" |
||||
|
}) |
||||
</script> |
</script> |
||||
|
|
||||
<div class="root"> |
<div class="root"> |
||||
<div class="title {navActive}" on:click={() => store.selectExistingNode(node.nodeId)} style="padding-left: {20 + (level * 20)}px"> |
<div |
||||
{@html getIcon(icon, 12)} <span style="margin-left: 1rem">{node.name}</span> |
class="title {navActive}" |
||||
</div> |
on:click={() => store.selectExistingNode(node.nodeId)} |
||||
{#if node.children} |
style="padding-left: {20 + level * 20}px"> |
||||
{#each node.children as child} |
{@html getIcon(icon, 12)} |
||||
<svelte:self node={child} |
<span style="margin-left: 1rem">{node.name}</span> |
||||
level={level+1} |
</div> |
||||
type="record"/> |
{#if node.children} |
||||
{/each} |
{#each node.children as child} |
||||
{/if} |
<svelte:self node={child} level={level + 1} type="record" /> |
||||
{#if node.indexes} |
{/each} |
||||
{#each node.indexes as index} |
{/if} |
||||
<svelte:self node={index} |
{#if node.indexes} |
||||
level={level+1} |
{#each node.indexes as index} |
||||
type="index"/> |
<svelte:self node={index} level={level + 1} type="index" /> |
||||
{/each} |
{/each} |
||||
{/if} |
{/if} |
||||
</div> |
</div> |
||||
|
|
||||
|
|
||||
<style> |
<style> |
||||
|
.root { |
||||
.root { |
|
||||
display: block; |
display: block; |
||||
font-size: .9rem; |
font-size: 0.9rem; |
||||
width: 100%; |
width: 100%; |
||||
cursor: pointer; |
cursor: pointer; |
||||
color: var(--secondary50); |
color: var(--secondary50); |
||||
font-weight: 500; |
font-weight: 500; |
||||
} |
} |
||||
|
|
||||
.title { |
.title { |
||||
padding-top: .5rem; |
padding-top: 0.5rem; |
||||
padding-right: .5rem; |
padding-right: 0.5rem; |
||||
} |
} |
||||
|
|
||||
.title:hover { |
.title:hover { |
||||
background-color: var(--secondary10); |
background-color: var(--secondary10); |
||||
} |
} |
||||
|
|
||||
.active { |
.active { |
||||
background-color: var(--primary10); |
background-color: var(--primary10); |
||||
} |
} |
||||
|
</style> |
||||
</style> |
|
||||
|
|||||
@ -1,43 +1,35 @@ |
|||||
<script> |
<script> |
||||
|
import { store } from "../builderStore" |
||||
|
import getIcon from "../common/icon" |
||||
|
|
||||
import {store} from "../builderStore"; |
export let name = "" |
||||
import getIcon from "../common/icon"; |
export let label = "" |
||||
|
|
||||
export let name = ""; |
let navActive = "" |
||||
export let label = ""; |
|
||||
|
|
||||
let navActive = ""; |
store.subscribe(db => { |
||||
|
navActive = db.activeNav === name ? "active" : "" |
||||
store.subscribe(db => { |
}) |
||||
navActive = (db.activeNav === name ? "active" : "") |
|
||||
}); |
|
||||
|
|
||||
const setActive = () => |
|
||||
store.setActiveNav(name); |
|
||||
|
|
||||
|
const setActive = () => store.setActiveNav(name) |
||||
</script> |
</script> |
||||
|
|
||||
<div class="nav-item {navActive}" on:click={setActive}> |
<div class="nav-item {navActive}" on:click={setActive}>{label}</div> |
||||
{label} |
|
||||
</div> |
|
||||
|
|
||||
|
|
||||
<style> |
<style> |
||||
|
.nav-item { |
||||
.nav-item { |
|
||||
padding: 1.5rem 1rem 0rem 1rem; |
padding: 1.5rem 1rem 0rem 1rem; |
||||
font-size: .9rem; |
font-size: 0.9rem; |
||||
font-weight: bold; |
font-weight: bold; |
||||
cursor: pointer; |
cursor: pointer; |
||||
flex: 0 0 auto; |
flex: 0 0 auto; |
||||
} |
} |
||||
|
|
||||
.nav-item:hover { |
.nav-item:hover { |
||||
background-color: var(--primary10); |
background-color: var(--primary10); |
||||
} |
} |
||||
|
|
||||
.active { |
.active { |
||||
background-color: var(--primary10); |
background-color: var(--primary10); |
||||
} |
} |
||||
|
</style> |
||||
</style> |
|
||||
|
|||||
@ -1,64 +1,59 @@ |
|||||
<script> |
<script> |
||||
|
import { searchAllComponents } from "./pagesParsing/searchComponents" |
||||
|
import { store } from "../builderStore" |
||||
|
|
||||
import { searchAllComponents } from "./pagesParsing/searchComponents"; |
export let onComponentChosen = () => {} |
||||
import { store } from "../builderStore"; |
|
||||
|
|
||||
export let onComponentChosen = () => {}; |
let phrase = "" |
||||
|
|
||||
let phrase = ""; |
components = $store.components |
||||
|
|
||||
components = $store.components; |
$: filteredComponents = !phrase ? [] : searchAllComponents(components, phrase) |
||||
|
|
||||
$: filteredComponents = |
|
||||
!phrase |
|
||||
? [] |
|
||||
: searchAllComponents(components, phrase); |
|
||||
</script> |
</script> |
||||
|
|
||||
<div class="root"> |
<div class="root"> |
||||
|
|
||||
<form class="uk-search uk-search-large"> |
<form class="uk-search uk-search-large"> |
||||
<span uk-search-icon></span> |
<span uk-search-icon /> |
||||
<input class="uk-search-input" |
<input |
||||
type="search" |
class="uk-search-input" |
||||
placeholder="Based on component..." |
type="search" |
||||
bind:value={phrase}> |
placeholder="Based on component..." |
||||
</form> |
bind:value={phrase} /> |
||||
|
</form> |
||||
<div> |
|
||||
{#each filteredComponents as component} |
<div> |
||||
<div class="component" on:click={() => onComponentChosen(component)}> |
{#each filteredComponents as component} |
||||
<div class="title">{component.name}</div> |
<div class="component" on:click={() => onComponentChosen(component)}> |
||||
<div class="description">{component.description}</div> |
<div class="title">{component.name}</div> |
||||
</div> |
<div class="description">{component.description}</div> |
||||
{/each} |
</div> |
||||
</div> |
{/each} |
||||
|
</div> |
||||
|
|
||||
</div> |
</div> |
||||
|
|
||||
<style> |
<style> |
||||
|
.component { |
||||
.component { |
padding: 5px; |
||||
padding:5px; |
|
||||
border-style: solid; |
border-style: solid; |
||||
border-width: 0 0 1px 0; |
border-width: 0 0 1px 0; |
||||
border-color: var(--lightslate); |
border-color: var(--lightslate); |
||||
cursor: pointer; |
cursor: pointer; |
||||
} |
} |
||||
|
|
||||
.component:hover { |
.component:hover { |
||||
background-color: var(--primary10); |
background-color: var(--primary10); |
||||
} |
} |
||||
|
|
||||
.component > .title { |
.component > .title { |
||||
font-size: 13pt; |
font-size: 13pt; |
||||
color: var(--secondary100); |
color: var(--secondary100); |
||||
} |
} |
||||
|
|
||||
.component > .description { |
.component > .description { |
||||
font-size: 10pt; |
font-size: 10pt; |
||||
color: var(--primary75); |
color: var(--primary75); |
||||
font-style: italic; |
font-style: italic; |
||||
} |
} |
||||
|
|
||||
</style> |
</style> |
||||
|
|||||
@ -1,184 +1,138 @@ |
|||||
<script> |
<script> |
||||
import { |
import { isRootComponent } from "./pagesParsing/searchComponents" |
||||
isRootComponent |
import { splitName } from "./pagesParsing/splitRootComponentName.js" |
||||
} from "./pagesParsing/searchComponents" |
import { store } from "../builderStore" |
||||
import { splitName } from "./pagesParsing/splitRootComponentName.js" |
import { find, sortBy } from "lodash/fp" |
||||
import { store } from "../builderStore"; |
|
||||
import { find, sortBy } from "lodash/fp"; |
export let onComponentChosen |
||||
|
export let onGeneratorChosen |
||||
export let onComponentChosen; |
export let allowGenerators |
||||
export let onGeneratorChosen; |
|
||||
export let allowGenerators; |
let screens = [] |
||||
|
let componentLibraries = [] |
||||
let screens = []; |
|
||||
let componentLibraries=[]; |
const addRootComponent = (c, all, isGenerator) => { |
||||
|
const { libName } = splitName(c.name) |
||||
const addRootComponent = (c, all, isGenerator) => { |
let group = find(r => r.libName === libName)(all) |
||||
const { libName } = splitName(c.name); |
|
||||
let group = find(r => r.libName === libName)(all); |
if (!group) { |
||||
|
group = { |
||||
if(!group) { |
libName, |
||||
group = { |
components: [], |
||||
libName, |
generators: [], |
||||
components: [], |
} |
||||
generators: [] |
|
||||
}; |
all.push(group) |
||||
|
} |
||||
all.push(group); |
|
||||
} |
if (isGenerator) { |
||||
|
group.generators.push(c) |
||||
if(isGenerator) { |
} else { |
||||
group.generators.push(c) |
group.components.push(c) |
||||
} else { |
} |
||||
group.components.push(c) |
} |
||||
} |
|
||||
|
$: { |
||||
}; |
const newComponentLibraries = [] |
||||
|
const newscreens = [] |
||||
$: { |
|
||||
|
for (let comp of sortBy(["name"])($store.components)) { |
||||
const newComponentLibraries = []; |
if (isRootComponent(comp)) { |
||||
const newscreens = []; |
addRootComponent(comp, newComponentLibraries, false) |
||||
|
} else { |
||||
for(let comp of sortBy(["name"])($store.components)) { |
newscreens.push(comp) |
||||
if(isRootComponent(comp)) { |
} |
||||
addRootComponent( |
} |
||||
comp, |
|
||||
newComponentLibraries, |
for (let generator of $store.generators) { |
||||
false); |
addRootComponent(generator, newComponentLibraries, true) |
||||
} else { |
} |
||||
newscreens.push(comp); |
|
||||
} |
screens = sortBy(["name"])(newscreens) |
||||
} |
componentLibraries = newComponentLibraries |
||||
|
} |
||||
for(let generator of $store.generators) { |
|
||||
addRootComponent( |
|
||||
generator, |
|
||||
newComponentLibraries, |
|
||||
true); |
|
||||
} |
|
||||
|
|
||||
screens = sortBy(["name"])(newscreens); |
|
||||
componentLibraries = newComponentLibraries; |
|
||||
}; |
|
||||
</script> |
</script> |
||||
|
|
||||
{#each componentLibraries as lib} |
{#each componentLibraries as lib} |
||||
<div class="library-header"> |
<div class="library-header">{lib.libName}</div> |
||||
{lib.libName} |
|
||||
</div> |
|
||||
|
|
||||
<div class="library-container"> |
<div class="library-container"> |
||||
|
|
||||
{#if allowGenerators} |
{#if allowGenerators} |
||||
<div class="inner-header"> |
<div class="inner-header">Generators</div> |
||||
Generators |
|
||||
</div> |
|
||||
|
|
||||
{#each lib.generators as generator} |
|
||||
|
|
||||
<div class="component" |
{#each lib.generators as generator} |
||||
on:click={() => onGeneratorChosen(generator)}> |
<div class="component" on:click={() => onGeneratorChosen(generator)}> |
||||
<div class="name"> |
<div class="name">{splitName(generator.name).componentName}</div> |
||||
{splitName(generator.name).componentName} |
<div class="description">{generator.description}</div> |
||||
</div> |
</div> |
||||
<div class="description"> |
{/each} |
||||
{generator.description} |
|
||||
</div> |
|
||||
</div> |
|
||||
|
|
||||
{/each} |
|
||||
{/if} |
{/if} |
||||
|
|
||||
<div class="inner-header"> |
<div class="inner-header">Components</div> |
||||
Components |
|
||||
</div> |
|
||||
|
|
||||
{#each lib.components as component} |
{#each lib.components as component} |
||||
|
<div class="component" on:click={() => onComponentChosen(component)}> |
||||
<div class="component" |
<div class="name">{splitName(component.name).componentName}</div> |
||||
on:click={() => onComponentChosen(component)}> |
<div class="description">{component.description}</div> |
||||
<div class="name"> |
</div> |
||||
{splitName(component.name).componentName} |
|
||||
</div> |
|
||||
<div class="description"> |
|
||||
{component.description} |
|
||||
</div> |
|
||||
</div> |
|
||||
|
|
||||
{/each} |
{/each} |
||||
|
|
||||
</div> |
</div> |
||||
|
|
||||
{/each} |
{/each} |
||||
|
|
||||
|
<div class="library-header">My Components</div> |
||||
<div class="library-header"> |
|
||||
My Components |
|
||||
</div> |
|
||||
|
|
||||
<div class="library-container"> |
<div class="library-container"> |
||||
|
|
||||
{#each screens as component} |
{#each screens as component} |
||||
|
<div class="component" on:click={() => onComponentChosen(component)}> |
||||
<div class="component" |
<div class="name">{component.name}</div> |
||||
on:click={() => onComponentChosen(component)}> |
<div class="description">{component.description}</div> |
||||
<div class="name"> |
|
||||
{component.name} |
|
||||
</div> |
|
||||
<div class="description"> |
|
||||
{component.description} |
|
||||
</div> |
|
||||
</div> |
</div> |
||||
|
{/each} |
||||
{/each} |
|
||||
|
|
||||
</div> |
</div> |
||||
|
|
||||
|
|
||||
<style> |
<style> |
||||
|
.library-header { |
||||
.library-header { |
|
||||
font-size: 1.1em; |
font-size: 1.1em; |
||||
border-color: var(--primary25); |
border-color: var(--primary25); |
||||
border-width: 1px 0px; |
border-width: 1px 0px; |
||||
border-style: solid; |
border-style: solid; |
||||
background-color: var(--primary10); |
background-color: var(--primary10); |
||||
padding: 5px 0; |
padding: 5px 0; |
||||
} |
} |
||||
|
|
||||
.library-container { |
.library-container { |
||||
padding: 0 0 10px 10px; |
padding: 0 0 10px 10px; |
||||
} |
} |
||||
|
|
||||
.inner-header { |
.inner-header { |
||||
font-size: 0.9em; |
font-size: 0.9em; |
||||
font-weight: bold; |
font-weight: bold; |
||||
margin-top: 7px; |
margin-top: 7px; |
||||
margin-bottom: 3px; |
margin-bottom: 3px; |
||||
} |
} |
||||
|
|
||||
.component { |
.component { |
||||
padding: 2px 0px; |
padding: 2px 0px; |
||||
cursor: pointer; |
cursor: pointer; |
||||
} |
} |
||||
|
|
||||
.component:hover { |
.component:hover { |
||||
background-color: var(--lightslate); |
background-color: var(--lightslate); |
||||
} |
} |
||||
|
|
||||
.component > .name { |
.component > .name { |
||||
color: var(--secondary100); |
color: var(--secondary100); |
||||
display: inline-block; |
display: inline-block; |
||||
} |
} |
||||
|
|
||||
.component > .description { |
.component > .description { |
||||
font-size: 0.8em; |
font-size: 0.8em; |
||||
color: var(--secondary75); |
color: var(--secondary75); |
||||
display: inline-block; |
display: inline-block; |
||||
margin-left: 10px; |
margin-left: 10px; |
||||
} |
} |
||||
|
|
||||
|
|
||||
|
|
||||
</style> |
</style> |
||||
|
|||||
@ -1,120 +1,114 @@ |
|||||
<script> |
<script> |
||||
import ComponentsHierarchyChildren from './ComponentsHierarchyChildren.svelte'; |
import ComponentsHierarchyChildren from "./ComponentsHierarchyChildren.svelte" |
||||
|
|
||||
import { |
|
||||
last, |
|
||||
sortBy, |
|
||||
map, |
|
||||
trimCharsStart, |
|
||||
trimChars, |
|
||||
join, |
|
||||
} from "lodash/fp"; |
|
||||
|
|
||||
import { pipe } from "../common/core"; |
|
||||
import { store } from "../builderStore"; |
|
||||
import { ArrowDownIcon } from '../common/Icons/' |
|
||||
|
|
||||
export let components = [] |
|
||||
|
|
||||
const joinPath = join("/"); |
|
||||
|
|
||||
const normalizedName = name => pipe(name, [ |
|
||||
trimCharsStart("./"), |
|
||||
trimCharsStart("~/"), |
|
||||
trimCharsStart("../"), |
|
||||
trimChars(" ") |
|
||||
]); |
|
||||
|
|
||||
const lastPartOfName = (c) => |
|
||||
last(c.name ? c.name.split("/") : c._component.split("/")) |
|
||||
|
|
||||
const isComponentSelected = (current, comp) => |
|
||||
current && |
|
||||
current.component && |
|
||||
comp.component && |
|
||||
current.component.name === comp.component.name |
|
||||
|
|
||||
const isFolderSelected = (current, folder) => |
|
||||
isInSubfolder(current, folder) |
|
||||
|
|
||||
$: _components = |
|
||||
pipe(components, [ |
|
||||
map(c => ({component: c, title:lastPartOfName(c)})), |
|
||||
sortBy("title") |
|
||||
]); |
|
||||
|
|
||||
function select_component(screen, component) { |
|
||||
store.setCurrentScreen(screen); |
|
||||
store.selectComponent(component); |
|
||||
} |
|
||||
|
|
||||
const isScreenSelected = component => |
|
||||
component.component && |
|
||||
$store.currentFrontEndItem && |
|
||||
component.component.name === $store.currentFrontEndItem.name; |
|
||||
|
|
||||
</script> |
import { last, sortBy, map, trimCharsStart, trimChars, join } from "lodash/fp" |
||||
|
|
||||
<div class="root"> |
import { pipe } from "../common/core" |
||||
|
import { store } from "../builderStore" |
||||
|
import { ArrowDownIcon } from "../common/Icons/" |
||||
|
|
||||
|
export let components = [] |
||||
|
|
||||
|
const joinPath = join("/") |
||||
|
|
||||
|
const normalizedName = name => |
||||
|
pipe(name, [ |
||||
|
trimCharsStart("./"), |
||||
|
trimCharsStart("~/"), |
||||
|
trimCharsStart("../"), |
||||
|
trimChars(" "), |
||||
|
]) |
||||
|
|
||||
|
const lastPartOfName = c => |
||||
|
last(c.name ? c.name.split("/") : c._component.split("/")) |
||||
|
|
||||
|
const isComponentSelected = (current, comp) => |
||||
|
current && |
||||
|
current.component && |
||||
|
comp.component && |
||||
|
current.component.name === comp.component.name |
||||
|
|
||||
{#each _components as component} |
const isFolderSelected = (current, folder) => isInSubfolder(current, folder) |
||||
<div class="hierarchy-item component" |
|
||||
class:selected={isComponentSelected($store.currentComponentInfo, component)} |
|
||||
on:click|stopPropagation={() => store.setCurrentScreen(component.component.name)}> |
|
||||
|
|
||||
<span class="icon" style="transform: rotate({isScreenSelected(component) ? 0 : -90}deg);"> |
$: _components = pipe(components, [ |
||||
{#if component.component.props && component.component.props._children} |
map(c => ({ component: c, title: lastPartOfName(c) })), |
||||
<ArrowDownIcon /> |
sortBy("title"), |
||||
{/if} |
]) |
||||
</span> |
|
||||
|
|
||||
<span class="title">{component.title}</span> |
function select_component(screen, component) { |
||||
</div> |
store.setCurrentScreen(screen) |
||||
|
store.selectComponent(component) |
||||
|
} |
||||
|
|
||||
{#if isScreenSelected(component) && component.component.props && component.component.props._children} |
const isScreenSelected = component => |
||||
<ComponentsHierarchyChildren components={component.component.props._children} |
component.component && |
||||
currentComponent={$store.currentComponentInfo} |
$store.currentFrontEndItem && |
||||
onSelect={child => select_component(component.component.name, child)} /> |
component.component.name === $store.currentFrontEndItem.name |
||||
|
</script> |
||||
|
|
||||
|
<div class="root"> |
||||
|
|
||||
|
{#each _components as component} |
||||
|
<div |
||||
|
class="hierarchy-item component" |
||||
|
class:selected={isComponentSelected($store.currentComponentInfo, component)} |
||||
|
on:click|stopPropagation={() => store.setCurrentScreen(component.component.name)}> |
||||
|
|
||||
|
<span |
||||
|
class="icon" |
||||
|
style="transform: rotate({isScreenSelected(component) ? 0 : -90}deg);"> |
||||
|
{#if component.component.props && component.component.props._children} |
||||
|
<ArrowDownIcon /> |
||||
{/if} |
{/if} |
||||
{/each} |
</span> |
||||
|
|
||||
|
<span class="title">{component.title}</span> |
||||
|
</div> |
||||
|
|
||||
|
{#if isScreenSelected(component) && component.component.props && component.component.props._children} |
||||
|
<ComponentsHierarchyChildren |
||||
|
components={component.component.props._children} |
||||
|
currentComponent={$store.currentComponentInfo} |
||||
|
onSelect={child => select_component(component.component.name, child)} /> |
||||
|
{/if} |
||||
|
{/each} |
||||
|
|
||||
</div> |
</div> |
||||
|
|
||||
<style> |
<style> |
||||
|
.root { |
||||
.root { |
|
||||
font-weight: 500; |
font-weight: 500; |
||||
font-size: 0.9rem; |
font-size: 0.9rem; |
||||
color: #828fa5; |
color: #828fa5; |
||||
} |
} |
||||
|
|
||||
.hierarchy-item { |
.hierarchy-item { |
||||
cursor: pointer; |
cursor: pointer; |
||||
padding: 11px 7px; |
padding: 11px 7px; |
||||
margin: 5px 0; |
margin: 5px 0; |
||||
border-radius: 5px; |
border-radius: 5px; |
||||
display: flex; |
display: flex; |
||||
align-items: center; |
align-items: center; |
||||
} |
} |
||||
|
|
||||
.hierarchy-item:hover { |
.hierarchy-item:hover { |
||||
/* color: var(--secondary); */ |
/* color: var(--secondary); */ |
||||
background: #fafafa; |
background: #fafafa; |
||||
} |
} |
||||
|
|
||||
.selected { |
.selected { |
||||
color: var(--button-text); |
color: var(--button-text); |
||||
background: var(--background-button)!important; |
background: var(--background-button) !important; |
||||
} |
} |
||||
|
|
||||
.title { |
.title { |
||||
margin-left: 10px; |
margin-left: 10px; |
||||
} |
} |
||||
|
|
||||
.icon { |
.icon { |
||||
display: inline-block; |
display: inline-block; |
||||
transition: 0.2s; |
transition: 0.2s; |
||||
width: 24px; |
width: 24px; |
||||
height: 24px; |
height: 24px; |
||||
} |
} |
||||
</style> |
</style> |
||||
|
|||||
@ -1,85 +1,71 @@ |
|||||
<script> |
<script> |
||||
import { store } from "../builderStore"; |
import { store } from "../builderStore" |
||||
import { map, join } from "lodash/fp"; |
import { map, join } from "lodash/fp" |
||||
import { pipe } from "../common/core"; |
import { pipe } from "../common/core" |
||||
import { buildPropsHierarchy } from "./pagesParsing/buildPropsHierarchy"; |
import { buildPropsHierarchy } from "./pagesParsing/buildPropsHierarchy" |
||||
|
|
||||
let iframe; |
let iframe |
||||
|
|
||||
$: iframe && console.log(iframe.contentDocument.head.insertAdjacentHTML('beforeend', '<style></style>')) |
$: iframe && |
||||
$: hasComponent = !!$store.currentFrontEndItem; |
console.log( |
||||
$: styles = hasComponent ? $store.currentFrontEndItem._css : ''; |
iframe.contentDocument.head.insertAdjacentHTML( |
||||
|
"beforeend", |
||||
|
'<style ✂prettier:content✂=""></style>' |
||||
|
) |
||||
|
) |
||||
|
$: hasComponent = !!$store.currentFrontEndItem |
||||
|
$: styles = hasComponent ? $store.currentFrontEndItem._css : "" |
||||
|
|
||||
$: stylesheetLinks = pipe($store.pages.stylesheets, [ |
$: stylesheetLinks = pipe($store.pages.stylesheets, [ |
||||
map(s => `<link rel="stylesheet" href="${s}"/>`), |
map(s => `<link rel="stylesheet" href="${s}"/>`), |
||||
join("\n") |
join("\n"), |
||||
]); |
]) |
||||
|
|
||||
$: appDefinition = { |
$: appDefinition = { |
||||
componentLibraries: $store.loadLibraryUrls(), |
componentLibraries: $store.loadLibraryUrls(), |
||||
props: buildPropsHierarchy( |
props: buildPropsHierarchy( |
||||
$store.components, |
$store.components, |
||||
$store.screens, |
$store.screens, |
||||
$store.currentFrontEndItem), |
$store.currentFrontEndItem |
||||
hierarchy: $store.hierarchy, |
), |
||||
appRootPath: "" |
hierarchy: $store.hierarchy, |
||||
}; |
appRootPath: "", |
||||
|
} |
||||
</script> |
</script> |
||||
|
|
||||
|
|
||||
<div class="component-container"> |
<div class="component-container"> |
||||
{#if hasComponent} |
{#if hasComponent} |
||||
<iframe style="height: 100%; width: 100%" |
<iframe |
||||
title="componentPreview" |
style="height: 100%; width: 100%" |
||||
bind:this={iframe} |
title="componentPreview" |
||||
srcdoc={ |
bind:this={iframe} |
||||
`<html> |
srcdoc={`<html> |
||||
|
|
||||
<head> |
<head> |
||||
${stylesheetLinks} |
${stylesheetLinks} |
||||
<script> |
<script ✂prettier:content✂="CiAgICAgICAgd2luZG93WyIjI0JVRElCQVNFX0FQUERFRklOSVRJT04jIyJdID0gJHtKU09OLnN0cmluZ2lmeShhcHBEZWZpbml0aW9uKX07CiAgICAgICAgd2luZG93WyIjI0JVRElCQVNFX1VJRlVOQ1RJT05TIl0gPSAkeyRzdG9yZS5jdXJyZW50U2NyZWVuRnVuY3Rpb25zfTsKICAgICAgICAKICAgICAgICBpbXBvcnQoJy9fYnVpbGRlci9idWRpYmFzZS1jbGllbnQuZXNtLm1qcycpCiAgICAgICAgLnRoZW4obW9kdWxlID0+IHsKICAgICAgICAgICAgbW9kdWxlLmxvYWRCdWRpYmFzZSh7IHdpbmRvdywgbG9jYWxTdG9yYWdlIH0pOwogICAgICAgIH0pCiAgICA=">{}</script> <style ✂prettier:content✂="CgogICAgICAgIGJvZHkgewogICAgICAgICAgICBib3gtc2l6aW5nOiBib3JkZXItYm94OwogICAgICAgICAgICBwYWRkaW5nOiAyMHB4OwogICAgICAgIH0KICAgICR7c3R5bGVzfQogICAg"></style></head> |
||||
window["##BUDIBASE_APPDEFINITION##"] = ${JSON.stringify(appDefinition)}; |
|
||||
window["##BUDIBASE_UIFUNCTIONS"] = ${$store.currentScreenFunctions}; |
|
||||
|
|
||||
import('/_builder/budibase-client.esm.mjs') |
|
||||
.then(module => { |
|
||||
module.loadBudibase({ window, localStorage }); |
|
||||
}) |
|
||||
</script> |
|
||||
<style> |
|
||||
|
|
||||
body { |
|
||||
box-sizing: border-box; |
|
||||
padding: 20px; |
|
||||
} |
|
||||
${styles} |
|
||||
</style> |
|
||||
</head> |
|
||||
<body> |
<body> |
||||
</body> |
</body> |
||||
</html>`}> |
</html>`} /> |
||||
</iframe> |
{/if} |
||||
{/if} |
|
||||
</div> |
</div> |
||||
|
|
||||
|
|
||||
<style> |
<style> |
||||
.component-container { |
.component-container { |
||||
grid-row-start: middle; |
grid-row-start: middle; |
||||
grid-column-start: middle; |
grid-column-start: middle; |
||||
position: relative; |
position: relative; |
||||
overflow: hidden; |
overflow: hidden; |
||||
padding-top: 56.25%; |
padding-top: 56.25%; |
||||
margin: auto; |
margin: auto; |
||||
} |
} |
||||
|
|
||||
.component-container iframe { |
.component-container iframe { |
||||
border: 0; |
border: 0; |
||||
height: 100%; |
height: 100%; |
||||
left: 0; |
left: 0; |
||||
position: absolute; |
position: absolute; |
||||
top: 0; |
top: 0; |
||||
width: 100%; |
width: 100%; |
||||
} |
} |
||||
</style> |
</style> |
||||
|
|||||
@ -1,90 +1,91 @@ |
|||||
<script> |
<script> |
||||
import PropsView from "./PropsView.svelte"; |
import PropsView from "./PropsView.svelte" |
||||
import { store } from "../builderStore"; |
import { store } from "../builderStore" |
||||
import IconButton from "../common/IconButton.svelte"; |
import IconButton from "../common/IconButton.svelte" |
||||
import Textbox from "../common/Textbox.svelte"; |
import Textbox from "../common/Textbox.svelte" |
||||
import Button from "../common/Button.svelte"; |
import Button from "../common/Button.svelte" |
||||
import { LayoutIcon, PaintIcon, TerminalIcon } from '../common/Icons/'; |
import { LayoutIcon, PaintIcon, TerminalIcon } from "../common/Icons/" |
||||
|
|
||||
import { |
import { cloneDeep, join, split, last } from "lodash/fp" |
||||
cloneDeep, |
import { assign } from "lodash" |
||||
join, |
|
||||
split, |
|
||||
last |
|
||||
} from "lodash/fp"; |
|
||||
import { assign } from "lodash"; |
|
||||
|
|
||||
$: component = $store.currentFrontEndItem; |
$: component = $store.currentFrontEndItem |
||||
$: componentInfo = $store.currentComponentInfo; |
$: componentInfo = $store.currentComponentInfo |
||||
$: components = $store.components; |
$: components = $store.components |
||||
|
|
||||
|
const updateComponent = doChange => doChange(cloneDeep(component)) |
||||
|
|
||||
const updateComponent = doChange => |
const onPropsChanged = newProps => { |
||||
doChange(cloneDeep(component)); |
updateComponent(newComponent => assign(newComponent.props, newProps)) |
||||
|
} |
||||
const onPropsChanged = newProps => { |
|
||||
updateComponent(newComponent => |
|
||||
assign(newComponent.props, newProps)); |
|
||||
} |
|
||||
</script> |
</script> |
||||
|
|
||||
<div class="root"> |
<div class="root"> |
||||
|
|
||||
<ul> |
<ul> |
||||
<li><button><PaintIcon /></button></li> |
<li> |
||||
<li><button><LayoutIcon /></button></li> |
<button> |
||||
<li><button><TerminalIcon /></button></li> |
<PaintIcon /> |
||||
</ul> |
</button> |
||||
|
</li> |
||||
<div class="component-props-container"> |
<li> |
||||
<PropsView |
<button> |
||||
{componentInfo} |
<LayoutIcon /> |
||||
{onPropsChanged} /> |
</button> |
||||
</div> |
</li> |
||||
|
<li> |
||||
|
<button> |
||||
|
<TerminalIcon /> |
||||
|
</button> |
||||
|
</li> |
||||
|
</ul> |
||||
|
|
||||
|
<div class="component-props-container"> |
||||
|
<PropsView {componentInfo} {onPropsChanged} /> |
||||
|
</div> |
||||
</div> |
</div> |
||||
|
|
||||
<style> |
<style> |
||||
.root { |
.root { |
||||
height: 100%; |
height: 100%; |
||||
display: flex; |
display: flex; |
||||
flex-direction: column; |
flex-direction: column; |
||||
|
} |
||||
} |
|
||||
|
.title > div:nth-child(1) { |
||||
.title > div:nth-child(1) { |
grid-column-start: name; |
||||
grid-column-start: name; |
color: var(--secondary100); |
||||
color: var(--secondary100); |
} |
||||
} |
|
||||
|
.title > div:nth-child(2) { |
||||
.title > div:nth-child(2) { |
grid-column-start: actions; |
||||
grid-column-start: actions; |
} |
||||
} |
|
||||
|
.component-props-container { |
||||
.component-props-container { |
flex: 1 1 auto; |
||||
flex: 1 1 auto; |
overflow-y: auto; |
||||
overflow-y: auto; |
} |
||||
} |
|
||||
|
ul { |
||||
ul { |
list-style: none; |
||||
list-style: none; |
display: flex; |
||||
display: flex; |
padding: 0; |
||||
padding: 0; |
} |
||||
} |
|
||||
|
li { |
||||
li { |
margin-right: 20px; |
||||
margin-right: 20px; |
background: none; |
||||
background: none; |
border-radius: 5px; |
||||
border-radius: 5px; |
width: 45px; |
||||
width: 45px; |
height: 45px; |
||||
height: 45px; |
} |
||||
} |
|
||||
|
li button { |
||||
li button { |
width: 100%; |
||||
width: 100%; |
height: 100%; |
||||
height: 100%; |
background: none; |
||||
background: none; |
border: none; |
||||
border: none; |
border-radius: 5px; |
||||
border-radius: 5px; |
padding: 12px; |
||||
padding: 12px; |
} |
||||
} |
|
||||
</style> |
</style> |
||||
|
|||||
@ -1,111 +1,106 @@ |
|||||
<script> |
<script> |
||||
import ComponentSelector from "./ComponentSelector.svelte"; |
import ComponentSelector from "./ComponentSelector.svelte" |
||||
import { store } from "../builderStore"; |
import { store } from "../builderStore" |
||||
import PropsView from "./PropsView.svelte"; |
import PropsView from "./PropsView.svelte" |
||||
import Textbox from "../common/Textbox.svelte"; |
import Textbox from "../common/Textbox.svelte" |
||||
import Button from "../common/Button.svelte"; |
import Button from "../common/Button.svelte" |
||||
import ButtonGroup from "../common/ButtonGroup.svelte"; |
import ButtonGroup from "../common/ButtonGroup.svelte" |
||||
import { pipe } from "../common/core"; |
import { pipe } from "../common/core" |
||||
import UIkit from "uikit"; |
import UIkit from "uikit" |
||||
import { isRootComponent } from "./pagesParsing/searchComponents"; |
import { isRootComponent } from "./pagesParsing/searchComponents" |
||||
import { splitName } from "./pagesParsing/splitRootComponentName.js" |
import { splitName } from "./pagesParsing/splitRootComponentName.js" |
||||
|
|
||||
import { |
import { find, filter, some, map, includes } from "lodash/fp" |
||||
find, filter, some, map, includes |
import { assign } from "lodash" |
||||
} from "lodash/fp"; |
|
||||
import { assign } from "lodash"; |
export const show = () => { |
||||
|
UIkit.modal(componentSelectorModal).show() |
||||
|
} |
||||
export const show = () => { |
|
||||
UIkit.modal(componentSelectorModal).show(); |
let componentSelectorModal |
||||
} |
let layoutComponents |
||||
|
let layoutComponent |
||||
let componentSelectorModal; |
let screens |
||||
let layoutComponents; |
let name = "" |
||||
let layoutComponent; |
let saveAttempted = false |
||||
let screens; |
|
||||
let name=""; |
store.subscribe(s => { |
||||
let saveAttempted=false; |
layoutComponents = pipe(s.components, [ |
||||
|
filter(c => c.container), |
||||
store.subscribe(s => { |
map(c => ({ name: c.name, ...splitName(c.name) })), |
||||
layoutComponents = pipe(s.components, [ |
]) |
||||
filter(c => c.container), |
|
||||
map(c => ({name:c.name, ...splitName(c.name)})) |
layoutComponent = layoutComponent |
||||
]); |
? find(c => c.name === layoutComponent.name)(layoutComponents) |
||||
|
: layoutComponents[0] |
||||
layoutComponent = layoutComponent |
|
||||
? find(c => c.name === layoutComponent.name)(layoutComponents) |
screens = s.screens |
||||
: layoutComponents[0]; |
}) |
||||
|
|
||||
screens = s.screens; |
const save = () => { |
||||
}); |
saveAttempted = true |
||||
|
|
||||
const save = () => { |
const isValid = |
||||
saveAttempted = true; |
name.length > 0 && !screenNameExists(name) && layoutComponent |
||||
|
|
||||
const isValid = name.length > 0 |
if (!isValid) return |
||||
&& !screenNameExists(name) |
|
||||
&& layoutComponent; |
store.createScreen(name, layoutComponent.name) |
||||
|
UIkit.modal(componentSelectorModal).hide() |
||||
if(!isValid) return; |
} |
||||
|
|
||||
store.createScreen(name, layoutComponent.name); |
const cancel = () => { |
||||
UIkit.modal(componentSelectorModal).hide(); |
UIkit.modal(componentSelectorModal).hide() |
||||
} |
} |
||||
|
|
||||
const cancel = () => { |
const screenNameExists = name => |
||||
UIkit.modal(componentSelectorModal).hide(); |
some(s => s.name.toLowerCase() === name.toLowerCase())(screens) |
||||
} |
|
||||
|
|
||||
const screenNameExists = (name) => |
|
||||
some(s => s.name.toLowerCase() === name.toLowerCase())(screens) |
|
||||
|
|
||||
</script> |
</script> |
||||
|
|
||||
<div bind:this={componentSelectorModal} id="new-component-modal" uk-modal> |
<div bind:this={componentSelectorModal} id="new-component-modal" uk-modal> |
||||
<div class="uk-modal-dialog" uk-overflow-auto> |
<div class="uk-modal-dialog" uk-overflow-auto> |
||||
|
|
||||
<div class="uk-modal-header"> |
<div class="uk-modal-header"> |
||||
<h1>New Screen</h1> |
<h1>New Screen</h1> |
||||
</div> |
</div> |
||||
|
|
||||
<div class="uk-modal-body uk-form-horizontal"> |
<div class="uk-modal-body uk-form-horizontal"> |
||||
<div class="uk-margin"> |
<div class="uk-margin"> |
||||
<label class="uk-form-label">Name</label> |
<label class="uk-form-label">Name</label> |
||||
<div class="uk-form-controls"> |
<div class="uk-form-controls"> |
||||
<input class="uk-input uk-form-small" |
<input |
||||
class:uk-form-danger={saveAttempted && (name.length === 0 || screenNameExists(name))} |
class="uk-input uk-form-small" |
||||
bind:value={name} > |
class:uk-form-danger={saveAttempted && (name.length === 0 || screenNameExists(name))} |
||||
</div> |
bind:value={name} /> |
||||
</div> |
</div> |
||||
|
</div> |
||||
<div class="uk-margin"> |
|
||||
<label class="uk-form-label">Layout Component</label> |
<div class="uk-margin"> |
||||
<div class="uk-form-controls"> |
<label class="uk-form-label">Layout Component</label> |
||||
<select class="uk-select uk-form-small" |
<div class="uk-form-controls"> |
||||
bind:value={layoutComponent} |
<select |
||||
class:uk-form-danger={saveAttempted && !layoutComponent}> |
class="uk-select uk-form-small" |
||||
{#each layoutComponents as comp} |
bind:value={layoutComponent} |
||||
<option value={comp}> |
class:uk-form-danger={saveAttempted && !layoutComponent}> |
||||
{comp.componentName} - {comp.libName} |
{#each layoutComponents as comp} |
||||
</option> |
<option value={comp}> |
||||
{/each} |
{comp.componentName} - {comp.libName} |
||||
</select> |
</option> |
||||
</div> |
{/each} |
||||
</div> |
</select> |
||||
|
|
||||
<ButtonGroup style="float: right;"> |
|
||||
<Button color="primary" grouped on:click={save}>Create Screen</Button> |
|
||||
<Button color="tertiary" grouped on:click={cancel}>Cancel</Button> |
|
||||
</ButtonGroup> |
|
||||
</div> |
</div> |
||||
|
</div> |
||||
|
|
||||
|
<ButtonGroup style="float: right;"> |
||||
|
<Button color="primary" grouped on:click={save}>Create Screen</Button> |
||||
|
<Button color="tertiary" grouped on:click={cancel}>Cancel</Button> |
||||
|
</ButtonGroup> |
||||
</div> |
</div> |
||||
|
</div> |
||||
</div> |
</div> |
||||
|
|
||||
|
|
||||
|
|
||||
<style> |
<style> |
||||
h1 { |
h1 { |
||||
font-size:1.2em; |
font-size: 1.2em; |
||||
} |
} |
||||
</style> |
</style> |
||||
|
|||||
@ -1,63 +1,66 @@ |
|||||
<script> |
<script> |
||||
|
import Textbox from "../common/Textbox.svelte" |
||||
|
import Dropdown from "../common/Dropdown.svelte" |
||||
|
import Button from "../common/Button.svelte" |
||||
|
import { store } from "../builderStore" |
||||
|
import { isRootComponent } from "./pagesParsing/searchComponents" |
||||
|
import { pipe } from "../common/core" |
||||
|
import { filter, find, concat } from "lodash/fp" |
||||
|
|
||||
import Textbox from "../common/Textbox.svelte"; |
const notSeletedComponent = { name: "(none selected)" } |
||||
import Dropdown from "../common/Dropdown.svelte"; |
|
||||
import Button from "../common/Button.svelte"; |
$: page = $store.pages[$store.currentPageName] |
||||
import { store } from "../builderStore"; |
$: title = page.index.title |
||||
import { isRootComponent } from "./pagesParsing/searchComponents"; |
$: components = pipe($store.components, [ |
||||
import { pipe } from "../common/core"; |
filter(store => !isRootComponent($store)), |
||||
import { |
concat([notSeletedComponent]), |
||||
filter, find, concat |
]) |
||||
} from "lodash/fp"; |
$: entryComponent = |
||||
|
find(c => c.name === page.appBody)(components) || notSeletedComponent |
||||
const notSeletedComponent = {name:"(none selected)"}; |
|
||||
|
const save = () => { |
||||
$: page = $store.pages[$store.currentPageName]; |
if (!title || !entryComponent || entryComponent === notSeletedComponent) |
||||
$: title = page.index.title; |
return |
||||
$: components = pipe($store.components, [ |
const page = { |
||||
filter(store => !isRootComponent($store)), |
index: { |
||||
concat([notSeletedComponent]) |
title, |
||||
]); |
}, |
||||
$: entryComponent = find(c => c.name === page.appBody)(components) || notSeletedComponent; |
appBody: entryComponent.name, |
||||
|
|
||||
|
|
||||
const save = () => { |
|
||||
if(!title || !entryComponent || entryComponent === notSeletedComponent) return; |
|
||||
const page = { |
|
||||
index: { |
|
||||
title |
|
||||
}, |
|
||||
appBody: entryComponent.name, |
|
||||
} |
|
||||
store.savePage(page); |
|
||||
} |
} |
||||
|
store.savePage(page) |
||||
|
} |
||||
</script> |
</script> |
||||
|
|
||||
<div class="root"> |
<div class="root"> |
||||
|
|
||||
<h3>{$store.currentPageName}</h3> |
<h3>{$store.currentPageName}</h3> |
||||
|
|
||||
<form class="uk-form-horizontal"> |
<form class="uk-form-horizontal"> |
||||
<Textbox bind:text={title} label="Title" hasError={!title}/> |
<Textbox bind:text={title} label="Title" hasError={!title} /> |
||||
<div class="help-text">The title of your page, displayed in the bowser tab</div> |
<div class="help-text"> |
||||
<Dropdown label="App Entry Component" |
The title of your page, displayed in the bowser tab |
||||
options={components} |
</div> |
||||
bind:selected={entryComponent} |
<Dropdown |
||||
textMember={(v) => v.name} /> |
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 class="help-text"> |
||||
<div style="margin-top: 20px"></div> |
The component that will be loaded into the body of the page |
||||
<Button on:click={save}>Save</Button> |
</div> |
||||
</form> |
<div style="margin-top: 20px" /> |
||||
|
<Button on:click={save}>Save</Button> |
||||
|
</form> |
||||
|
|
||||
</div> |
</div> |
||||
|
|
||||
<style> |
<style> |
||||
.root { |
.root { |
||||
padding: 15px; |
padding: 15px; |
||||
} |
} |
||||
.help-text { |
.help-text { |
||||
color: var(--slate); |
color: var(--slate); |
||||
font-size: 10pt; |
font-size: 10pt; |
||||
} |
} |
||||
</style> |
</style> |
||||
|
|||||
@ -1,73 +1,80 @@ |
|||||
<script> |
<script> |
||||
import { store } from "../builderStore"; |
import { store } from "../builderStore" |
||||
import getIcon from "../common/icon"; |
import getIcon from "../common/icon" |
||||
|
|
||||
const getPage = (s, name) => { |
const getPage = (s, name) => { |
||||
const props = s.pages[name]; |
const props = s.pages[name] |
||||
return ({name, props}); |
return { name, props } |
||||
} |
} |
||||
|
|
||||
const pages = [{ |
const pages = [ |
||||
title: 'Main', |
{ |
||||
id: 'main' |
title: "Main", |
||||
}, { |
id: "main", |
||||
title: 'Login', |
}, |
||||
id: 'unauthenticated' |
{ |
||||
}] |
title: "Login", |
||||
|
id: "unauthenticated", |
||||
|
}, |
||||
|
] |
||||
|
|
||||
store.setCurrentPage('main') |
store.setCurrentPage("main") |
||||
</script> |
</script> |
||||
|
|
||||
<div class="root"> |
<div class="root"> |
||||
<select id="page" name="select" on:change={({target}) => store.setCurrentPage(target.value)}> |
<select |
||||
|
id="page" |
||||
|
name="select" |
||||
|
on:change={({ target }) => store.setCurrentPage(target.value)}> |
||||
|
|
||||
{#each pages as {title, id}} |
{#each pages as { title, id }} |
||||
<option value="{id}">Page: {title}</option> |
<option value={id}>Page: {title}</option> |
||||
{/each} |
{/each} |
||||
|
|
||||
</select> |
</select> |
||||
<span class="arrow">{@html getIcon("chevron-down","24")}</span> |
<span class="arrow"> |
||||
|
{@html getIcon('chevron-down', '24')} |
||||
|
</span> |
||||
</div> |
</div> |
||||
|
|
||||
<style> |
<style> |
||||
.root { |
.root { |
||||
padding-bottom: 10px; |
padding-bottom: 10px; |
||||
font-size: .9rem; |
font-size: 0.9rem; |
||||
color: var(--secondary50); |
color: var(--secondary50); |
||||
font-weight: bold; |
font-weight: bold; |
||||
position: relative; |
position: relative; |
||||
} |
} |
||||
|
|
||||
|
select { |
||||
|
display: block; |
||||
|
font-size: 16px; |
||||
|
font-family: sans-serif; |
||||
|
font-weight: 700; |
||||
|
color: #444; |
||||
|
line-height: 1.3; |
||||
|
padding: 1em 2.6em 0.9em 1.4em; |
||||
|
width: 100%; |
||||
|
max-width: 100%; |
||||
|
box-sizing: border-box; |
||||
|
margin: 0; |
||||
|
border: none; |
||||
|
border-radius: 0.5em; |
||||
|
-moz-appearance: none; |
||||
|
-webkit-appearance: none; |
||||
|
appearance: none; |
||||
|
background-color: #fafafa; |
||||
|
} |
||||
|
|
||||
select { |
.arrow { |
||||
display: block; |
position: absolute; |
||||
font-size: 16px; |
right: 10px; |
||||
font-family: sans-serif; |
top: 0; |
||||
font-weight: 700; |
bottom: 0; |
||||
color: #444; |
margin: auto; |
||||
line-height: 1.3; |
width: 30px; |
||||
padding: 1em 2.6em 0.9em 1.4em; |
height: 30px; |
||||
width: 100%; |
pointer-events: none; |
||||
max-width: 100%; |
color: var(--primary100); |
||||
box-sizing: border-box; |
} |
||||
margin: 0; |
|
||||
border: none; |
|
||||
border-radius: .5em; |
|
||||
-moz-appearance: none; |
|
||||
-webkit-appearance: none; |
|
||||
appearance: none; |
|
||||
background-color: #fafafa; |
|
||||
} |
|
||||
|
|
||||
.arrow { |
|
||||
position: absolute; |
|
||||
right: 10px; |
|
||||
top: 0; |
|
||||
bottom: 0; |
|
||||
margin: auto; |
|
||||
width: 30px; |
|
||||
height: 30px; |
|
||||
pointer-events: none; |
|
||||
color: var(--primary100); |
|
||||
} |
|
||||
</style> |
</style> |
||||
|
|||||
@ -1,52 +1,50 @@ |
|||||
<script> |
<script> |
||||
import Checkbox from "../common/Checkbox.svelte"; |
import Checkbox from "../common/Checkbox.svelte" |
||||
import Textbox from "../common/Textbox.svelte"; |
import Textbox from "../common/Textbox.svelte" |
||||
import Dropdown from "../common/Dropdown.svelte"; |
import Dropdown from "../common/Dropdown.svelte" |
||||
import StateBindingControl from "./StateBindingControl.svelte"; |
import StateBindingControl from "./StateBindingControl.svelte" |
||||
|
|
||||
export let setProp = () => {}; |
export let setProp = () => {} |
||||
export let index; |
export let index |
||||
export let prop_name; |
export let prop_name |
||||
export let prop_value; |
export let prop_value |
||||
export let prop_type = {}; |
export let prop_type = {} |
||||
|
|
||||
$: isOdd = (index % 2 !== 0); |
$: isOdd = index % 2 !== 0 |
||||
|
|
||||
const setComponentProp = (props) => { |
const setComponentProp = props => { |
||||
setProp(propDef.____name, props); |
setProp(propDef.____name, props) |
||||
} |
} |
||||
</script> |
</script> |
||||
|
|
||||
|
<div class="root"> |
||||
<div class="root" > |
{#if prop_type !== 'event'} |
||||
{#if prop_type !== "event" } |
|
||||
|
|
||||
<h5>{prop_name}</h5> |
<h5>{prop_name}</h5> |
||||
<StateBindingControl value={prop_value} |
<StateBindingControl |
||||
type={prop_type} |
value={prop_value} |
||||
options={prop_type.options} |
type={prop_type} |
||||
onChanged={v => setProp(prop_name, v)}/> |
options={prop_type.options} |
||||
|
onChanged={v => setProp(prop_name, v)} /> |
||||
{/if} |
{/if} |
||||
</div> |
</div> |
||||
|
|
||||
<style> |
<style> |
||||
.root { |
.root { |
||||
height: 40px; |
height: 40px; |
||||
margin-bottom: 15px; |
margin-bottom: 15px; |
||||
display: grid; |
display: grid; |
||||
grid-template-rows: 1fr; |
grid-template-rows: 1fr; |
||||
grid-template-columns: 70px 1fr; |
grid-template-columns: 70px 1fr; |
||||
grid-gap: 10px; |
grid-gap: 10px; |
||||
} |
} |
||||
|
|
||||
h5 { |
h5 { |
||||
word-wrap: break-word; |
word-wrap: break-word; |
||||
font-size: 12px; |
font-size: 12px; |
||||
font-weight: 700; |
font-weight: 700; |
||||
color: #163057; |
color: #163057; |
||||
opacity: 0.6; |
opacity: 0.6; |
||||
padding-top: 12px; |
padding-top: 12px; |
||||
margin-bottom: 0; |
margin-bottom: 0; |
||||
} |
} |
||||
</style> |
</style> |
||||
|
|||||
@ -1,70 +1,72 @@ |
|||||
<script> |
<script> |
||||
import { some, includes, filter } from "lodash/fp"; |
import { some, includes, filter } from "lodash/fp" |
||||
import Textbox from "../common/Textbox.svelte"; |
import Textbox from "../common/Textbox.svelte" |
||||
import Dropdown from "../common/Dropdown.svelte"; |
import Dropdown from "../common/Dropdown.svelte" |
||||
import PropControl from "./PropControl.svelte"; |
import PropControl from "./PropControl.svelte" |
||||
import IconButton from "../common/IconButton.svelte"; |
import IconButton from "../common/IconButton.svelte" |
||||
|
|
||||
export let componentInfo; |
export let componentInfo |
||||
export let onPropChanged = () => {}; |
export let onPropChanged = () => {} |
||||
export let components; |
export let components |
||||
|
|
||||
let errors = []; |
let errors = [] |
||||
let props = {}; |
let props = {} |
||||
|
|
||||
const props_to_ignore = ['_component','_children', '_styles', '_code', '_id']; |
const props_to_ignore = ["_component", "_children", "_styles", "_code", "_id"] |
||||
|
|
||||
$: propDefs = componentInfo && Object.entries(componentInfo).filter(([name])=> !props_to_ignore.includes(name)); |
$: propDefs = |
||||
|
componentInfo && |
||||
function find_type(prop_name) { |
Object.entries(componentInfo).filter( |
||||
if(!componentInfo._component) return; |
([name]) => !props_to_ignore.includes(name) |
||||
return components.find(({name}) => name === componentInfo._component).props[prop_name]; |
) |
||||
} |
|
||||
|
function find_type(prop_name) { |
||||
let setProp = (name, value) => { |
if (!componentInfo._component) return |
||||
onPropChanged(name, value); |
return components.find(({ name }) => name === componentInfo._component) |
||||
} |
.props[prop_name] |
||||
|
} |
||||
const fieldHasError = (propName) => |
|
||||
some(e => e.propName === propName)(errors); |
let setProp = (name, value) => { |
||||
|
onPropChanged(name, value) |
||||
|
} |
||||
|
|
||||
|
const fieldHasError = propName => some(e => e.propName === propName)(errors) |
||||
</script> |
</script> |
||||
|
|
||||
<div class="root"> |
<div class="root"> |
||||
|
|
||||
<form class="uk-form-stacked form-root"> |
<form class="uk-form-stacked form-root"> |
||||
{#each propDefs as [prop_name, prop_value], index} |
{#each propDefs as [prop_name, prop_value], index} |
||||
|
<div class="prop-container"> |
||||
<div class="prop-container"> |
|
||||
|
|
||||
<PropControl {setProp} |
<PropControl |
||||
{prop_name} |
{setProp} |
||||
{prop_value} |
{prop_name} |
||||
prop_type={find_type(prop_name)} |
{prop_value} |
||||
{index} |
prop_type={find_type(prop_name)} |
||||
disabled={false} /> |
{index} |
||||
|
disabled={false} /> |
||||
|
|
||||
</div> |
</div> |
||||
|
{/each} |
||||
|
|
||||
{/each} |
</form> |
||||
|
|
||||
</form> |
|
||||
|
|
||||
</div> |
</div> |
||||
|
|
||||
|
|
||||
<style> |
<style> |
||||
.root { |
.root { |
||||
font-size:10pt; |
font-size: 10pt; |
||||
width: 100%; |
width: 100%; |
||||
} |
} |
||||
|
|
||||
.form-root { |
.form-root { |
||||
display: flex; |
display: flex; |
||||
flex-wrap: wrap; |
flex-wrap: wrap; |
||||
} |
} |
||||
|
|
||||
.prop-container { |
.prop-container { |
||||
flex: 1 1 auto; |
flex: 1 1 auto; |
||||
min-width: 250px; |
min-width: 250px; |
||||
} |
} |
||||
</style> |
</style> |
||||
|
|||||
@ -1,137 +1,134 @@ |
|||||
<script> |
<script> |
||||
import { store } from "../builderStore"; |
import { store } from "../builderStore" |
||||
import Textbox from "../common/Textbox.svelte"; |
import Textbox from "../common/Textbox.svelte" |
||||
import Button from "../common/Button.svelte"; |
import Button from "../common/Button.svelte" |
||||
import IconButton from "../common/IconButton.svelte"; |
import IconButton from "../common/IconButton.svelte" |
||||
import { libraryDependencies } from "./pagesParsing/findDependencies"; |
import { libraryDependencies } from "./pagesParsing/findDependencies" |
||||
import UIkit from "uikit"; |
import UIkit from "uikit" |
||||
|
|
||||
let addNewLib = ""; |
let addNewLib = "" |
||||
let addNewStylesheet = ""; |
let addNewStylesheet = "" |
||||
let modalElement; |
let modalElement |
||||
|
|
||||
$: components = $store.components; |
$: components = $store.components |
||||
|
|
||||
const removeLibrary = lib => { |
const removeLibrary = lib => { |
||||
const dependencies = libraryDependencies(components, lib); |
const dependencies = libraryDependencies(components, lib) |
||||
if(dependencies.length > 0) return; |
if (dependencies.length > 0) return |
||||
store.removeComponentLibrary(lib); |
store.removeComponentLibrary(lib) |
||||
} |
} |
||||
|
|
||||
const addLib = () => { |
const addLib = () => { |
||||
store.addComponentLibrary(addNewLib) |
store.addComponentLibrary(addNewLib).then(() => { |
||||
.then(() => { |
addNewLib = "" |
||||
addNewLib = ""; |
}) |
||||
}); |
} |
||||
} |
|
||||
|
const removeStylesheet = stylesheet => { |
||||
const removeStylesheet = stylesheet => { |
store.removeStylesheet(stylesheet) |
||||
store.removeStylesheet(stylesheet); |
} |
||||
} |
|
||||
|
const addStylesheet = () => { |
||||
const addStylesheet = () => { |
if (addNewStylesheet) store.addStylesheet(addNewStylesheet) |
||||
if(addNewStylesheet) |
} |
||||
store.addStylesheet(addNewStylesheet); |
|
||||
} |
export const close = () => { |
||||
|
UIkit.modal(modalElement).hide() |
||||
export const close = () => { |
} |
||||
UIkit.modal(modalElement).hide(); |
|
||||
} |
export const show = () => { |
||||
|
UIkit.modal(modalElement).show() |
||||
export const show = () => { |
} |
||||
UIkit.modal(modalElement).show(); |
|
||||
} |
|
||||
</script> |
</script> |
||||
|
|
||||
<div bind:this={modalElement} id="new-component-modal" uk-modal> |
<div bind:this={modalElement} id="new-component-modal" uk-modal> |
||||
<div class="uk-modal-dialog"> |
<div class="uk-modal-dialog"> |
||||
|
|
||||
<div class="uk-modal-header header"> |
<div class="uk-modal-header header"> |
||||
<div>Settings</div> |
<div>Settings</div> |
||||
<div> |
<div> |
||||
<IconButton icon="x" |
<IconButton icon="x" on:click={close} /> |
||||
on:click={close}/> |
</div> |
||||
</div> |
</div> |
||||
</div> |
|
||||
|
<div class="uk-modal-body uk-form-horizontal"> |
||||
<div class="uk-modal-body uk-form-horizontal"> |
|
||||
|
<div class="section-container"> |
||||
<div class="section-container"> |
<p> |
||||
<p>Component Libraries |
Component Libraries |
||||
<span> |
<span> |
||||
<input bind:value={addNewLib} /> |
<input bind:value={addNewLib} /> |
||||
<Button color="primary-outline" |
<Button color="primary-outline" on:click={addLib}>Add</Button> |
||||
on:click={addLib}>Add</Button> |
</span> |
||||
</span> |
</p> |
||||
</p> |
{#each $store.pages.componentLibraries as lib} |
||||
{#each $store.pages.componentLibraries as lib} |
<div> |
||||
<div> |
<span class="row-text">{lib}</span> |
||||
<span class="row-text">{lib}</span> |
<IconButton icon="x" on:click={() => removeLibrary(lib)} /> |
||||
<IconButton icon="x" |
</div> |
||||
on:click={() => removeLibrary(lib)}/> |
{/each} |
||||
</div> |
</div> |
||||
{/each} |
|
||||
</div> |
<div class="section-container"> |
||||
|
<p> |
||||
|
Stylesheets |
||||
<div class="section-container"> |
<span> |
||||
<p>Stylesheets |
<input bind:value={addNewStylesheet} /> |
||||
<span> |
<Button color="primary-outline" on:click={addStylesheet}> |
||||
<input bind:value={addNewStylesheet} /> |
Add |
||||
<Button color="primary-outline" |
</Button> |
||||
on:click={addStylesheet} >Add</Button> |
</span> |
||||
</span> |
</p> |
||||
</p> |
{#each $store.pages.stylesheets as stylesheet} |
||||
{#each $store.pages.stylesheets as stylesheet} |
<div> |
||||
<div> |
<span class="row-text">{stylesheet}</span> |
||||
<span class="row-text">{stylesheet}</span> |
<IconButton |
||||
<IconButton icon="x" |
icon="x" |
||||
on:click={() => removeStylesheet(stylesheet)}/> |
on:click={() => removeStylesheet(stylesheet)} /> |
||||
</div> |
</div> |
||||
{/each} |
{/each} |
||||
</div> |
</div> |
||||
|
|
||||
|
|
||||
</div> |
|
||||
</div> |
</div> |
||||
|
</div> |
||||
</div> |
</div> |
||||
|
|
||||
<style> |
<style> |
||||
.section-container { |
.section-container { |
||||
padding: 15px; |
padding: 15px; |
||||
border-style: dotted; |
border-style: dotted; |
||||
border-width: 1px; |
border-width: 1px; |
||||
border-color: var(--lightslate); |
border-color: var(--lightslate); |
||||
border-radius: 2px; |
border-radius: 2px; |
||||
} |
} |
||||
|
|
||||
.section-container:nth-child(1) { |
.section-container:nth-child(1) { |
||||
margin-bottom: 15px; |
margin-bottom: 15px; |
||||
} |
} |
||||
|
|
||||
.row-text { |
.row-text { |
||||
margin-right: 15px; |
margin-right: 15px; |
||||
color: var(--primary100); |
color: var(--primary100); |
||||
} |
} |
||||
|
|
||||
input { |
input { |
||||
margin-right: 15px; |
margin-right: 15px; |
||||
} |
} |
||||
|
|
||||
p > span { |
p > span { |
||||
margin-left: 30px; |
margin-left: 30px; |
||||
} |
} |
||||
|
|
||||
.header { |
.header { |
||||
display: grid; |
display: grid; |
||||
grid-template-columns: [title] 1fr [icon] auto; |
grid-template-columns: [title] 1fr [icon] auto; |
||||
} |
} |
||||
|
|
||||
.header > div:nth-child(1) { |
.header > div:nth-child(1) { |
||||
grid-column-start: title; |
grid-column-start: title; |
||||
} |
} |
||||
|
|
||||
.header > div:nth-child(2) { |
.header > div:nth-child(2) { |
||||
grid-column-start: icon; |
grid-column-start: icon; |
||||
} |
} |
||||
</style> |
</style> |
||||
|
|||||
@ -1,163 +1,160 @@ |
|||||
<script> |
<script> |
||||
import IconButton from "../common/IconButton.svelte"; |
import IconButton from "../common/IconButton.svelte" |
||||
import Input from "../common/Input.svelte"; |
import Input from "../common/Input.svelte" |
||||
import { |
import { isBinding, getBinding, setBinding } from "../common/binding" |
||||
isBinding, getBinding, setBinding |
|
||||
} from "../common/binding"; |
export let value = "" |
||||
|
export let onChanged = () => {} |
||||
export let value=""; |
export let type = "" |
||||
export let onChanged= () => {}; |
export let options = [] |
||||
export let type=""; |
|
||||
export let options=[]; |
let isBound = false |
||||
|
let bindingPath = "" |
||||
let isBound=false; |
let bindingFallbackValue = "" |
||||
let bindingPath=""; |
let bindingSource = "store" |
||||
let bindingFallbackValue=""; |
let isExpanded = false |
||||
let bindingSource="store"; |
let forceIsBound = false |
||||
let isExpanded = false; |
let canOnlyBind = false |
||||
let forceIsBound = false; |
|
||||
let canOnlyBind = false; |
$: { |
||||
|
canOnlyBind = type === "state" |
||||
$: { |
if (!forceIsBound && canOnlyBind) forceIsBound = true |
||||
canOnlyBind = type === "state"; |
|
||||
if(!forceIsBound && canOnlyBind) |
isBound = forceIsBound || isBinding(value) |
||||
forceIsBound = true; |
|
||||
|
if (isBound) { |
||||
isBound= forceIsBound || isBinding(value); |
const binding = getBinding(value) |
||||
|
bindingPath = binding.path |
||||
if(isBound) { |
bindingFallbackValue = binding.fallback |
||||
const binding = getBinding(value); |
bindingSource = binding.source || "store" |
||||
bindingPath= binding.path; |
} else { |
||||
bindingFallbackValue= binding.fallback; |
bindingPath = "" |
||||
bindingSource = binding.source || "store"; |
bindingFallbackValue = "" |
||||
} else { |
bindingSource = "store" |
||||
bindingPath=""; |
|
||||
bindingFallbackValue=""; |
|
||||
bindingSource="store"; |
|
||||
} |
|
||||
} |
} |
||||
|
} |
||||
|
|
||||
const clearBinding = () => { |
const clearBinding = () => { |
||||
forceIsBound = false; |
forceIsBound = false |
||||
onChanged(""); |
onChanged("") |
||||
} |
} |
||||
|
|
||||
const bind = (path, fallback, source) => { |
|
||||
if(!path) { |
|
||||
clearBinding(""); |
|
||||
return; |
|
||||
} |
|
||||
const binding = setBinding({path, fallback, source}); |
|
||||
onChanged(binding); |
|
||||
} |
|
||||
|
|
||||
const setBindingPath = ev => { |
const bind = (path, fallback, source) => { |
||||
forceIsBound = canOnlyBind; |
if (!path) { |
||||
bind(ev.target.value, bindingFallbackValue, bindingSource) |
clearBinding("") |
||||
|
return |
||||
} |
} |
||||
|
const binding = setBinding({ path, fallback, source }) |
||||
const setBindingFallback = ev => { |
onChanged(binding) |
||||
bind(bindingPath, ev.target.value, bindingSource); |
} |
||||
} |
|
||||
|
const setBindingPath = ev => { |
||||
const setBindingSource = ev => { |
forceIsBound = canOnlyBind |
||||
bind(bindingPath, bindingFallbackValue, ev.target.value); |
bind(ev.target.value, bindingFallbackValue, bindingSource) |
||||
} |
} |
||||
|
|
||||
|
const setBindingFallback = ev => { |
||||
|
bind(bindingPath, ev.target.value, bindingSource) |
||||
|
} |
||||
|
|
||||
|
const setBindingSource = ev => { |
||||
|
bind(bindingPath, bindingFallbackValue, ev.target.value) |
||||
|
} |
||||
</script> |
</script> |
||||
|
|
||||
{#if isBound} |
{#if isBound} |
||||
<div> |
<div> |
||||
<div class="bound-header"> |
<div class="bound-header"> |
||||
<div>{isExpanded ? "" : bindingPath}</div> |
<div>{isExpanded ? '' : bindingPath}</div> |
||||
<IconButton icon={isExpanded ? "chevron-up" : "chevron-down"} |
<IconButton |
||||
size="12" |
icon={isExpanded ? 'chevron-up' : 'chevron-down'} |
||||
on:click={() => isExpanded=!isExpanded}/> |
size="12" |
||||
{#if !canOnlyBind} |
on:click={() => (isExpanded = !isExpanded)} /> |
||||
<IconButton icon="trash" |
{#if !canOnlyBind} |
||||
size="12" |
<IconButton icon="trash" size="12" on:click={clearBinding} /> |
||||
on:click={clearBinding}/> |
{/if} |
||||
{/if} |
|
||||
</div> |
|
||||
{#if isExpanded} |
|
||||
<div> |
|
||||
<div class="binding-prop-label">Binding Path</div> |
|
||||
<input class="uk-input uk-form-small" |
|
||||
value={bindingPath} |
|
||||
on:change={setBindingPath} > |
|
||||
<div class="binding-prop-label">Fallback Value</div> |
|
||||
<input class="uk-input uk-form-small" |
|
||||
value={bindingFallbackValue} |
|
||||
on:change={setBindingFallback} > |
|
||||
<div class="binding-prop-label">Binding Source</div> |
|
||||
<select class="uk-select uk-form-small" |
|
||||
value={bindingSource} |
|
||||
on:change={setBindingSource}> |
|
||||
|
|
||||
<option>store</option> |
|
||||
<option>context</option> |
|
||||
|
|
||||
</select> |
|
||||
</div> |
|
||||
{/if} |
|
||||
|
|
||||
</div> |
</div> |
||||
|
{#if isExpanded} |
||||
|
<div> |
||||
|
<div class="binding-prop-label">Binding Path</div> |
||||
|
<input |
||||
|
class="uk-input uk-form-small" |
||||
|
value={bindingPath} |
||||
|
on:change={setBindingPath} /> |
||||
|
<div class="binding-prop-label">Fallback Value</div> |
||||
|
<input |
||||
|
class="uk-input uk-form-small" |
||||
|
value={bindingFallbackValue} |
||||
|
on:change={setBindingFallback} /> |
||||
|
<div class="binding-prop-label">Binding Source</div> |
||||
|
<select |
||||
|
class="uk-select uk-form-small" |
||||
|
value={bindingSource} |
||||
|
on:change={setBindingSource}> |
||||
|
|
||||
|
<option>store</option> |
||||
|
<option>context</option> |
||||
|
|
||||
|
</select> |
||||
|
</div> |
||||
|
{/if} |
||||
|
|
||||
|
</div> |
||||
{:else} |
{:else} |
||||
<div class="unbound-container"> |
<div class="unbound-container"> |
||||
|
|
||||
{#if type === "bool"} |
{#if type === 'bool'} |
||||
<div> |
<div> |
||||
<IconButton icon={value == true ? "check-square" : "square"} |
<IconButton |
||||
size="19" |
icon={value == true ? 'check-square' : 'square'} |
||||
on:click={() => onChanged(!value)} /> |
size="19" |
||||
</div> |
on:click={() => onChanged(!value)} /> |
||||
{:else if type === "options"} |
</div> |
||||
<select class="uk-select uk-form-small" |
{:else if type === 'options'} |
||||
value={value} |
<select |
||||
on:change={ev => onChanged(ev.target.value)}> |
class="uk-select uk-form-small" |
||||
{#each options as option} |
{value} |
||||
<option value={option}>{option}</option> |
on:change={ev => onChanged(ev.target.value)}> |
||||
{/each} |
{#each options as option} |
||||
</select> |
<option value={option}>{option}</option> |
||||
{:else} |
{/each} |
||||
<Input |
</select> |
||||
on:change={ev => onChanged(ev.target.value)} |
{:else} |
||||
bind:value={value} /> |
<Input on:change={ev => onChanged(ev.target.value)} bind:value /> |
||||
{/if} |
{/if} |
||||
|
|
||||
</div> |
</div> |
||||
{/if} |
{/if} |
||||
|
|
||||
|
|
||||
<style> |
<style> |
||||
.unbound-container { |
.unbound-container { |
||||
display:flex; |
display: flex; |
||||
} |
} |
||||
|
|
||||
.bound-header { |
.bound-header { |
||||
display: flex; |
display: flex; |
||||
} |
} |
||||
|
|
||||
.bound-header > div:nth-child(1) { |
.bound-header > div:nth-child(1) { |
||||
flex: 1 0 auto; |
flex: 1 0 auto; |
||||
width: 30px; |
width: 30px; |
||||
color: var(--secondary50); |
color: var(--secondary50); |
||||
padding-left: 5px; |
padding-left: 5px; |
||||
} |
} |
||||
|
|
||||
.binding-prop-label { |
.binding-prop-label { |
||||
color: var(--secondary50); |
color: var(--secondary50); |
||||
} |
} |
||||
|
|
||||
input { |
input { |
||||
font-size: 12px; |
font-size: 12px; |
||||
font-weight: 700; |
font-weight: 700; |
||||
color: #163057; |
color: #163057; |
||||
opacity: 0.7; |
opacity: 0.7; |
||||
padding: 5px 10px; |
padding: 5px 10px; |
||||
box-sizing: border-box; |
box-sizing: border-box; |
||||
border: 1px solid #DBDBDB; |
border: 1px solid #dbdbdb; |
||||
border-radius: 2px; |
border-radius: 2px; |
||||
outline: none; |
outline: none; |
||||
} |
} |
||||
</style> |
</style> |
||||
|
|||||
@ -1,180 +1,178 @@ |
|||||
<script> |
<script> |
||||
import ComponentsHierarchy from "./ComponentsHierarchy.svelte"; |
import ComponentsHierarchy from "./ComponentsHierarchy.svelte" |
||||
import PagesList from "./PagesList.svelte" |
import PagesList from "./PagesList.svelte" |
||||
import { store } from "../builderStore"; |
import { store } from "../builderStore" |
||||
import IconButton from "../common/IconButton.svelte"; |
import IconButton from "../common/IconButton.svelte" |
||||
import Modal from "../common/Modal.svelte"; |
import Modal from "../common/Modal.svelte" |
||||
import NewComponent from "./NewComponent.svelte"; |
import NewComponent from "./NewComponent.svelte" |
||||
import CurrentItemPreview from "./CurrentItemPreview.svelte"; |
import CurrentItemPreview from "./CurrentItemPreview.svelte" |
||||
import SettingsView from "./SettingsView.svelte"; |
import SettingsView from "./SettingsView.svelte" |
||||
import PageView from "./PageView.svelte"; |
import PageView from "./PageView.svelte" |
||||
import ComponentsPaneSwitcher from "./ComponentsPaneSwitcher.svelte"; |
import ComponentsPaneSwitcher from "./ComponentsPaneSwitcher.svelte" |
||||
|
|
||||
let newComponentPicker; |
let newComponentPicker |
||||
|
|
||||
const newComponent = () => { |
const newComponent = () => { |
||||
newComponentPicker.show(); |
newComponentPicker.show() |
||||
} |
} |
||||
|
|
||||
let settingsView; |
let settingsView |
||||
const settings = () => { |
const settings = () => { |
||||
settingsView.show(); |
settingsView.show() |
||||
} |
} |
||||
</script> |
</script> |
||||
|
|
||||
<div class="root"> |
<div class="root"> |
||||
|
|
||||
<div class="ui-nav"> |
<div class="ui-nav"> |
||||
|
|
||||
<div class="pages-list-container"> |
<div class="pages-list-container"> |
||||
<div class="nav-group-header"> |
<div class="nav-group-header"> |
||||
|
|
||||
<span class="navigator-title">Navigator</span> |
<span class="navigator-title">Navigator</span> |
||||
</div> |
</div> |
||||
<div class="nav-items-container"> |
<div class="nav-items-container"> |
||||
<PagesList /> |
<PagesList /> |
||||
</div> |
</div> |
||||
</div> |
</div> |
||||
|
|
||||
<div class="components-list-container"> |
<div class="components-list-container"> |
||||
<div class="nav-group-header"> |
<div class="nav-group-header"> |
||||
|
|
||||
<span class="components-nav-header">Screens</span> |
|
||||
<div> |
|
||||
<button on:click={newComponent}>+</button> |
|
||||
</div> |
|
||||
</div> |
|
||||
<div class="nav-items-container"> |
|
||||
<ComponentsHierarchy components={$store.screens}/> |
|
||||
</div> |
|
||||
</div> |
|
||||
|
|
||||
|
<span class="components-nav-header">Screens</span> |
||||
|
<div> |
||||
|
<button on:click={newComponent}>+</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="nav-items-container"> |
||||
|
<ComponentsHierarchy components={$store.screens} /> |
||||
|
</div> |
||||
</div> |
</div> |
||||
|
|
||||
<div class="preview-pane"> |
</div> |
||||
{#if $store.currentFrontEndType === "screen"} |
|
||||
<CurrentItemPreview /> |
|
||||
{:else if $store.currentFrontEndType === "page"} |
|
||||
<PageView /> |
|
||||
{/if} |
|
||||
</div> |
|
||||
|
|
||||
{#if $store.currentFrontEndType === "screen"} |
<div class="preview-pane"> |
||||
<div class="components-pane"> |
{#if $store.currentFrontEndType === 'screen'} |
||||
<ComponentsPaneSwitcher /> |
<CurrentItemPreview /> |
||||
</div> |
{:else if $store.currentFrontEndType === 'page'} |
||||
|
<PageView /> |
||||
{/if} |
{/if} |
||||
|
</div> |
||||
|
|
||||
</div> |
{#if $store.currentFrontEndType === 'screen'} |
||||
|
<div class="components-pane"> |
||||
|
<ComponentsPaneSwitcher /> |
||||
|
</div> |
||||
|
{/if} |
||||
|
|
||||
|
</div> |
||||
|
|
||||
<NewComponent bind:this={newComponentPicker}/> |
<NewComponent bind:this={newComponentPicker} /> |
||||
<SettingsView bind:this={settingsView} /> |
<SettingsView bind:this={settingsView} /> |
||||
|
|
||||
|
|
||||
<style> |
<style> |
||||
button { |
button { |
||||
cursor: pointer; |
cursor: pointer; |
||||
outline: none; |
outline: none; |
||||
border: none; |
border: none; |
||||
border-radius: 5px; |
border-radius: 5px; |
||||
background: var(--background-button); |
background: var(--background-button); |
||||
|
|
||||
width: 1.8rem; |
width: 1.8rem; |
||||
height: 1.8rem; |
height: 1.8rem; |
||||
padding-bottom: 10px; |
padding-bottom: 10px; |
||||
|
|
||||
display: flex; |
display: flex; |
||||
justify-content: center; |
justify-content: center; |
||||
align-items: center; |
align-items: center; |
||||
|
|
||||
font-size: 1.2rem; |
font-size: 1.2rem; |
||||
font-weight: 700; |
font-weight: 700; |
||||
color: var(--button-text); |
color: var(--button-text); |
||||
} |
} |
||||
|
|
||||
.root { |
.root { |
||||
display: grid; |
display: grid; |
||||
grid-template-columns: 290px 1fr 300px; |
grid-template-columns: 290px 1fr 300px; |
||||
height: 100%; |
height: 100%; |
||||
width: 100%; |
width: 100%; |
||||
background: #fafafa; |
background: #fafafa; |
||||
} |
} |
||||
|
|
||||
.ui-nav { |
.ui-nav { |
||||
grid-column: 1; |
grid-column: 1; |
||||
background-color: var(--secondary5); |
background-color: var(--secondary5); |
||||
height: 100%; |
height: 100%; |
||||
padding: 0 1.5rem 0rem 1.5rem |
padding: 0 1.5rem 0rem 1.5rem; |
||||
} |
} |
||||
|
|
||||
.preview-pane { |
.preview-pane { |
||||
grid-column: 2; |
grid-column: 2; |
||||
margin: 80px 60px; |
margin: 80px 60px; |
||||
background: #fff; |
background: #fff; |
||||
border-radius: 5px; |
border-radius: 5px; |
||||
box-shadow: 0 0px 6px rgba(0,0,0,0.05) |
box-shadow: 0 0px 6px rgba(0, 0, 0, 0.05); |
||||
} |
} |
||||
|
|
||||
.components-pane { |
.components-pane { |
||||
grid-column: 3; |
grid-column: 3; |
||||
background-color: var(--secondary5); |
background-color: var(--secondary5); |
||||
min-height: 0px; |
min-height: 0px; |
||||
overflow-y: hidden; |
overflow-y: hidden; |
||||
} |
} |
||||
|
|
||||
.components-nav-header { |
.components-nav-header { |
||||
font-size: 0.75rem; |
font-size: 0.75rem; |
||||
color: #999; |
color: #999; |
||||
text-transform: uppercase; |
text-transform: uppercase; |
||||
} |
} |
||||
|
|
||||
.nav-group-header { |
.nav-group-header { |
||||
font-size: .9rem; |
font-size: 0.9rem; |
||||
padding-left: 1rem; |
padding-left: 1rem; |
||||
} |
} |
||||
|
|
||||
.nav-items-container { |
.nav-items-container { |
||||
padding: 1rem 0rem 0rem 0rem; |
padding: 1rem 0rem 0rem 0rem; |
||||
} |
} |
||||
|
|
||||
.nav-group-header { |
.nav-group-header { |
||||
display: flex; |
display: flex; |
||||
padding: 2rem 0 0 0; |
padding: 2rem 0 0 0; |
||||
font-size: .9rem; |
font-size: 0.9rem; |
||||
font-weight: bold; |
font-weight: bold; |
||||
justify-content: space-between; |
justify-content: space-between; |
||||
align-items: center; |
align-items: center; |
||||
} |
} |
||||
|
|
||||
.nav-group-header>div:nth-child(1) { |
.nav-group-header > div:nth-child(1) { |
||||
padding: 0rem .5rem 0rem 0rem; |
padding: 0rem 0.5rem 0rem 0rem; |
||||
vertical-align: bottom; |
vertical-align: bottom; |
||||
grid-column-start: icon; |
grid-column-start: icon; |
||||
margin-right: 5px; |
margin-right: 5px; |
||||
} |
} |
||||
|
|
||||
.nav-group-header>span:nth-child(2) { |
.nav-group-header > span:nth-child(2) { |
||||
margin-left:5px; |
margin-left: 5px; |
||||
vertical-align: bottom; |
vertical-align: bottom; |
||||
grid-column-start: title; |
grid-column-start: title; |
||||
margin-top:auto; |
margin-top: auto; |
||||
} |
} |
||||
|
|
||||
.nav-group-header>div:nth-child(3) { |
.nav-group-header > div:nth-child(3) { |
||||
vertical-align: bottom; |
vertical-align: bottom; |
||||
grid-column-start: button; |
grid-column-start: button; |
||||
cursor: pointer; |
cursor: pointer; |
||||
color: var(--primary75); |
color: var(--primary75); |
||||
} |
} |
||||
|
|
||||
.nav-group-header>div:nth-child(3):hover { |
.nav-group-header > div:nth-child(3):hover { |
||||
color: var(--primary75); |
color: var(--primary75); |
||||
} |
} |
||||
|
|
||||
.navigator-title { |
.navigator-title { |
||||
text-transform: uppercase; |
text-transform: uppercase; |
||||
font-weight: 400; |
font-weight: 400; |
||||
color: #999; |
color: #999; |
||||
} |
} |
||||
</style> |
</style> |
||||
|
|||||
@ -1,12 +1,8 @@ |
|||||
<script> |
<script> |
||||
export let text=""; |
export let text = "" |
||||
export let className="" |
export let className = "" |
||||
|
|
||||
export let _bb; |
|
||||
|
|
||||
|
|
||||
|
export let _bb |
||||
</script> |
</script> |
||||
|
|
||||
<h1 class={className}> |
<h1 class={className}>{text}</h1> |
||||
{text} |
|
||||
</h1> |
|
||||
|
|||||
@ -1,18 +1,14 @@ |
|||||
<script> |
<script> |
||||
|
export let _children = [] |
||||
export let _children = []; |
export let className = "" |
||||
export let className=""; |
export let onLoad |
||||
export let onLoad; |
export let _bb |
||||
export let _bb; |
|
||||
|
let rootDiv |
||||
let rootDiv; |
$: { |
||||
$:{ |
if (_bb && rootDiv && _children && _children.length) |
||||
if(_bb && rootDiv && _children && _children.length) |
_bb.hydrateChildren(_children, rootDiv) |
||||
_bb.hydrateChildren(_children, rootDiv); |
} |
||||
} |
|
||||
|
|
||||
|
|
||||
</script> |
</script> |
||||
|
|
||||
<div class="{className}" bind:this={rootDiv}> |
<div class={className} bind:this={rootDiv} /> |
||||
</div> |
|
||||
|
|||||
@ -1,12 +1,8 @@ |
|||||
<script> |
<script> |
||||
export let text=""; |
export let text = "" |
||||
export let className="" |
export let className = "" |
||||
|
|
||||
export let _bb; |
|
||||
|
|
||||
|
|
||||
|
export let _bb |
||||
</script> |
</script> |
||||
|
|
||||
<h1 class={className}> |
<h1 class={className}>{text}</h1> |
||||
{text} |
|
||||
</h1> |
|
||||
|
|||||
@ -1,12 +1,8 @@ |
|||||
<script> |
<script> |
||||
export let text=""; |
export let text = "" |
||||
export let className="" |
export let className = "" |
||||
|
|
||||
export let _bb; |
|
||||
|
|
||||
|
|
||||
|
export let _bb |
||||
</script> |
</script> |
||||
|
|
||||
<h1 class={className}> |
<h1 class={className}>{text}</h1> |
||||
{text} |
|
||||
</h1> |
|
||||
|
|||||
@ -1,12 +1,8 @@ |
|||||
<script> |
<script> |
||||
export let text=""; |
export let text = "" |
||||
export let className="" |
export let className = "" |
||||
|
|
||||
export let _bb; |
|
||||
|
|
||||
|
|
||||
|
export let _bb |
||||
</script> |
</script> |
||||
|
|
||||
<h3 class={className}> |
<h3 class={className}>{text}</h3> |
||||
{text} |
|
||||
</h3> |
|
||||
|
|||||
@ -1,12 +1,8 @@ |
|||||
<script> |
<script> |
||||
export let text=""; |
export let text = "" |
||||
export let className="" |
export let className = "" |
||||
|
|
||||
export let _bb; |
|
||||
|
|
||||
|
|
||||
|
export let _bb |
||||
</script> |
</script> |
||||
|
|
||||
<h4 class={className}> |
<h4 class={className}>{text}</h4> |
||||
{text} |
|
||||
</h4> |
|
||||
|
|||||
@ -1,12 +1,8 @@ |
|||||
<script> |
<script> |
||||
export let text=""; |
export let text = "" |
||||
export let className="" |
export let className = "" |
||||
|
|
||||
export let _bb; |
|
||||
|
|
||||
|
|
||||
|
export let _bb |
||||
</script> |
</script> |
||||
|
|
||||
<h6 class={className}> |
<h6 class={className}>{text}</h6> |
||||
{text} |
|
||||
</h6> |
|
||||
|
|||||
@ -1,14 +1,10 @@ |
|||||
<script> |
<script> |
||||
import {buildStyle} from "./buildStyle"; |
import { buildStyle } from "./buildStyle" |
||||
|
|
||||
export let text=""; |
|
||||
export let className="" |
|
||||
|
|
||||
export let _bb; |
|
||||
|
|
||||
|
export let text = "" |
||||
|
export let className = "" |
||||
|
|
||||
|
export let _bb |
||||
</script> |
</script> |
||||
|
|
||||
<h1 class={className}> |
<h1 class={className}>{text}</h1> |
||||
{text} |
|
||||
</h1> |
|
||||
|
|||||
@ -1,22 +1,17 @@ |
|||||
<script> |
<script> |
||||
|
export let value = "" |
||||
|
export let className = "" |
||||
|
export let type = "text" |
||||
|
|
||||
export let value=""; |
export let _bb |
||||
export let className = ""; |
|
||||
export let type = "text"; |
|
||||
|
|
||||
export let _bb; |
let actualValue = "" |
||||
|
|
||||
let actualValue = ""; |
|
||||
|
|
||||
const onchange = (ev) => { |
|
||||
if(_bb) { |
|
||||
_bb.setStateFromBinding(_bb.props.value, ev.target.value); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
const onchange = ev => { |
||||
|
if (_bb) { |
||||
|
_bb.setStateFromBinding(_bb.props.value, ev.target.value) |
||||
|
} |
||||
|
} |
||||
</script> |
</script> |
||||
|
|
||||
<input class={className} |
<input class={className} {type} {value} on:change={onchange} /> |
||||
type={type} |
|
||||
value={value} |
|
||||
on:change={onchange}/> |
|
||||
|
|||||
@ -1,27 +1,23 @@ |
|||||
<script> |
<script> |
||||
|
export let value = "" |
||||
|
export let className = "" |
||||
|
export let type = "text" |
||||
|
export let options = [] |
||||
|
|
||||
export let value=""; |
export let _bb |
||||
export let className = ""; |
|
||||
export let type = "text"; |
|
||||
export let options = []; |
|
||||
|
|
||||
export let _bb; |
let actualValue = "" |
||||
|
|
||||
let actualValue = ""; |
|
||||
|
|
||||
const onchange = (ev) => { |
|
||||
if(_bb) { |
|
||||
_bb.setStateFromBinding(_bb.props.value, ev.target.value); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
const onchange = ev => { |
||||
|
if (_bb) { |
||||
|
_bb.setStateFromBinding(_bb.props.value, ev.target.value) |
||||
|
} |
||||
|
} |
||||
</script> |
</script> |
||||
|
|
||||
<select class={className} |
<select class={className} {value} on:change={onchange}> |
||||
value={value} |
<option /> |
||||
on:change={onchange}> |
{#each options as opt} |
||||
<option></option> |
<option id={opt.id ? opt.id : opt.value}>{opt.value}</option> |
||||
{#each options as opt} |
{/each} |
||||
<option id={opt.id ? opt.id : opt.value}>{opt.value}</option> |
|
||||
{/each} |
|
||||
</select> |
</select> |
||||
|
|||||
@ -1,82 +1,74 @@ |
|||||
<script> |
<script> |
||||
|
export let columns = [] |
||||
|
export let data = "" |
||||
|
export let tableClass = "" |
||||
|
export let theadClass = "" |
||||
|
export let tbodyClass = "" |
||||
|
export let trClass = "" |
||||
|
export let thClass = "" |
||||
|
export let onRowClick |
||||
|
|
||||
export let columns=[]; |
export let _bb |
||||
export let data=""; |
|
||||
export let tableClass=""; |
|
||||
export let theadClass=""; |
|
||||
export let tbodyClass=""; |
|
||||
export let trClass=""; |
|
||||
export let thClass=""; |
|
||||
export let onRowClick; |
|
||||
|
|
||||
export let _bb; |
|
||||
|
|
||||
const rowClickHandler = (row) => () => { |
|
||||
_bb.call(onRowClick, row); |
|
||||
} |
|
||||
|
|
||||
const cellValue = (colIndex, row) => { |
|
||||
const val = _bb.getStateOrValue( |
|
||||
_bb.props.columns[colIndex].value |
|
||||
, row) |
|
||||
return val; |
|
||||
} |
|
||||
|
|
||||
|
const rowClickHandler = row => () => { |
||||
|
_bb.call(onRowClick, row) |
||||
|
} |
||||
|
|
||||
|
const cellValue = (colIndex, row) => { |
||||
|
const val = _bb.getStateOrValue(_bb.props.columns[colIndex].value, row) |
||||
|
return val |
||||
|
} |
||||
</script> |
</script> |
||||
|
|
||||
<table class={tableClass}> |
<table class={tableClass}> |
||||
<thead class={theadClass}> |
<thead class={theadClass}> |
||||
<tr class={trClass}> |
<tr class={trClass}> |
||||
{#each columns as col} |
{#each columns as col} |
||||
<th class={thClass}>{col.title}</th> |
<th class={thClass}>{col.title}</th> |
||||
{/each} |
{/each} |
||||
</tr> |
</tr> |
||||
</thead> |
</thead> |
||||
<tbody class={tbodyClass}> |
<tbody class={tbodyClass}> |
||||
{#if data} |
{#if data} |
||||
{#each data as row} |
{#each data as row} |
||||
<tr class={trClass} |
<tr class={trClass} on:click={rowClickHandler(row)}> |
||||
on:click={rowClickHandler(row)} > |
{#each columns as col, index} |
||||
{#each columns as col, index} |
|
||||
<th class={thClass}>{cellValue(index, row)}</th> |
<th class={thClass}>{cellValue(index, row)}</th> |
||||
{/each} |
{/each} |
||||
</tr> |
</tr> |
||||
{/each} |
{/each} |
||||
{/if} |
{/if} |
||||
</tbody> |
</tbody> |
||||
</table> |
</table> |
||||
|
|
||||
<style> |
<style> |
||||
|
.table-default { |
||||
.table-default { |
|
||||
width: 100%; |
width: 100%; |
||||
margin-bottom: 1rem; |
margin-bottom: 1rem; |
||||
color: #212529; |
color: #212529; |
||||
border-collapse: collapse; |
border-collapse: collapse; |
||||
} |
} |
||||
|
|
||||
.table-default .thead-default .th-default { |
.table-default .thead-default .th-default { |
||||
vertical-align: bottom; |
vertical-align: bottom; |
||||
border-bottom: 2px solid #dee2e6; |
border-bottom: 2px solid #dee2e6; |
||||
font-weight: bold; |
font-weight: bold; |
||||
} |
} |
||||
|
|
||||
.table-default .th-default { |
.table-default .th-default { |
||||
padding: .75rem; |
padding: 0.75rem; |
||||
vertical-align: top; |
vertical-align: top; |
||||
border-top: 1px solid #dee2e6; |
border-top: 1px solid #dee2e6; |
||||
font-weight: normal; |
font-weight: normal; |
||||
} |
} |
||||
|
|
||||
.th-default { |
.th-default { |
||||
text-align: inherit; |
text-align: inherit; |
||||
} |
} |
||||
|
|
||||
.table-default .tbody-default .tr-default:hover { |
.table-default .tbody-default .tr-default:hover { |
||||
color: #212529; |
color: #212529; |
||||
background-color: rgba(0,0,0,.075); |
background-color: rgba(0, 0, 0, 0.075); |
||||
cursor: pointer; |
cursor: pointer; |
||||
} |
} |
||||
|
</style> |
||||
</style> |
|
||||
|
|||||