forked from tsai/budibase
committed by
GitHub
46 changed files with 364 additions and 1215 deletions
@ -1,14 +0,0 @@ |
|||||
import resolve from "rollup-plugin-node-resolve" |
|
||||
|
|
||||
export default { |
|
||||
input: "src/generators.js", |
|
||||
output: [ |
|
||||
{ |
|
||||
file: "dist/generators.js", |
|
||||
format: "esm", |
|
||||
name: "budibaseStandardComponents", |
|
||||
sourcemap: "inline", |
|
||||
}, |
|
||||
], |
|
||||
plugins: [resolve()], |
|
||||
} |
|
||||
@ -1,4 +0,0 @@ |
|||||
export { forms } from "./generators/formsGenerator" |
|
||||
export { indexTables } from "./generators/indexTablesGenerator" |
|
||||
export { app } from "./generators/appGenerator" |
|
||||
export { recordHomePageComponents as recordHomepages } from "./generators/recordHomePageGenerator" |
|
||||
@ -1,37 +0,0 @@ |
|||||
import { |
|
||||
navContentComponentName, |
|
||||
selectNavContent, |
|
||||
} from "./selectedNavContentGenerator" |
|
||||
import { recordHomepages } from "./recordHomePageGenerator" |
|
||||
export const app = ({ records, indexes, helpers }) => [ |
|
||||
{ |
|
||||
name: "Application Root", |
|
||||
inherits: "@budibase/bootstrap-components/nav", |
|
||||
props: { |
|
||||
items: recordHomepages({ indexes, records }).map(navItem), |
|
||||
orientation: "horizontal", |
|
||||
alignment: "start", |
|
||||
fill: false, |
|
||||
pills: true, |
|
||||
selectedItem: { |
|
||||
"##bbstate": "selectedNav", |
|
||||
"##bbstatefallback": `${records[0].name}`, |
|
||||
"##bbsource": "store", |
|
||||
}, |
|
||||
className: "p-3", |
|
||||
}, |
|
||||
}, |
|
||||
{ |
|
||||
name: "Login", |
|
||||
inherits: "@budibase/standard-components/login", |
|
||||
props: {}, |
|
||||
}, |
|
||||
...selectNavContent({ records, indexes, helpers }), |
|
||||
] |
|
||||
|
|
||||
export const navItem = ({ record }) => ({ |
|
||||
title: record.collectionName, |
|
||||
component: { |
|
||||
_component: navContentComponentName(record), |
|
||||
}, |
|
||||
}) |
|
||||
@ -1,18 +0,0 @@ |
|||||
export const buttons = () => [ |
|
||||
{ |
|
||||
name: "common/Primary Button", |
|
||||
description: "Bootstrap primary button ", |
|
||||
inherits: "@budibase/standard-components/button", |
|
||||
props: { |
|
||||
className: "btn btn-primary", |
|
||||
}, |
|
||||
}, |
|
||||
{ |
|
||||
name: "common/Default Button", |
|
||||
description: "Bootstrap default button", |
|
||||
inherits: "@budibase/standard-components/button", |
|
||||
props: { |
|
||||
className: "btn btn-secondary", |
|
||||
}, |
|
||||
}, |
|
||||
] |
|
||||
@ -1,128 +0,0 @@ |
|||||
import { buttons } from "./buttonGenerators" |
|
||||
|
|
||||
export const forms = ({ records, indexes, helpers }) => [ |
|
||||
...records.map(root), |
|
||||
...buttons({ records, indexes, helpers }), |
|
||||
] |
|
||||
|
|
||||
export const formName = record => `${record.name}/${record.name} Form` |
|
||||
|
|
||||
const root = record => ({ |
|
||||
name: formName(record), |
|
||||
description: `Control for creating/updating '${record.nodeKey()}' `, |
|
||||
inherits: "@budibase/standard-components/container", |
|
||||
props: { |
|
||||
className: "p-1", |
|
||||
children: [ |
|
||||
{ |
|
||||
component: { |
|
||||
_component: "@budibase/standard-components/h3", |
|
||||
text: `Edit ${record.name}`, |
|
||||
}, |
|
||||
}, |
|
||||
form(record), |
|
||||
saveCancelButtons(record), |
|
||||
], |
|
||||
}, |
|
||||
}) |
|
||||
|
|
||||
const form = record => ({ |
|
||||
component: { |
|
||||
_component: "@budibase/standard-components/form", |
|
||||
formControls: record.fields.map(f => formControl(record, f)), |
|
||||
}, |
|
||||
}) |
|
||||
|
|
||||
const formControl = (record, field) => { |
|
||||
if ( |
|
||||
field.type === "string" && |
|
||||
field.typeOptions.values && |
|
||||
field.typeOptions.values.length > 0 |
|
||||
) { |
|
||||
return { |
|
||||
control: { |
|
||||
_component: "@budibase/standard-components/select", |
|
||||
options: field.typeOptions.values.map(v => ({ id: v, value: v })), |
|
||||
value: { |
|
||||
"##bbstate": `${record.name}.${field.name}`, |
|
||||
"##bbsource": "store", |
|
||||
}, |
|
||||
className: "form-control", |
|
||||
}, |
|
||||
label: field.label, |
|
||||
} |
|
||||
} else { |
|
||||
return { |
|
||||
control: { |
|
||||
_component: "@budibase/standard-components/input", |
|
||||
value: { |
|
||||
"##bbstate": `${record.name}.${field.name}`, |
|
||||
"##bbsource": "store", |
|
||||
}, |
|
||||
className: "form-control", |
|
||||
type: |
|
||||
field.type === "string" |
|
||||
? "text" |
|
||||
: field.type === "datetime" |
|
||||
? "date" |
|
||||
: field.type === "number" |
|
||||
? "number" |
|
||||
: "text", |
|
||||
}, |
|
||||
label: field.label, |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
const saveCancelButtons = record => ({ |
|
||||
component: { |
|
||||
_component: "@budibase/standard-components/stackpanel", |
|
||||
direction: "horizontal", |
|
||||
children: [ |
|
||||
paddedPanelForButton({ |
|
||||
_component: "common/Primary Button", |
|
||||
contentText: `Save ${record.name}`, |
|
||||
onClick: [ |
|
||||
{ |
|
||||
"##eventHandlerType": "Save Record", |
|
||||
parameters: { |
|
||||
statePath: `${record.name}`, |
|
||||
}, |
|
||||
}, |
|
||||
{ |
|
||||
"##eventHandlerType": "Set State", |
|
||||
parameters: { |
|
||||
path: `isEditing${record.name}`, |
|
||||
value: "", |
|
||||
}, |
|
||||
}, |
|
||||
], |
|
||||
}), |
|
||||
paddedPanelForButton({ |
|
||||
_component: "common/Default Button", |
|
||||
contentText: `Cancel`, |
|
||||
onClick: [ |
|
||||
{ |
|
||||
"##eventHandlerType": "Set State", |
|
||||
parameters: { |
|
||||
path: `isEditing${record.name}`, |
|
||||
value: "", |
|
||||
}, |
|
||||
}, |
|
||||
], |
|
||||
}), |
|
||||
], |
|
||||
}, |
|
||||
}) |
|
||||
|
|
||||
const paddedPanelForButton = button => ({ |
|
||||
control: { |
|
||||
_component: "@budibase/standard-components/container", |
|
||||
className: "btn-group", |
|
||||
children: [ |
|
||||
{ |
|
||||
component: button, |
|
||||
}, |
|
||||
], |
|
||||
}, |
|
||||
}) |
|
||||
@ -1,14 +0,0 @@ |
|||||
export const getRecordPath = () => { |
|
||||
const parts = [] |
|
||||
|
|
||||
const add = current => { |
|
||||
parts.push(current.name) |
|
||||
if (current.parent().type === "root") { |
|
||||
return |
|
||||
} |
|
||||
|
|
||||
add(current.parent()) |
|
||||
} |
|
||||
|
|
||||
return parts.reverse().join("/") |
|
||||
} |
|
||||
@ -1,53 +0,0 @@ |
|||||
import { getRecordPath } from "./getRecordPath" |
|
||||
|
|
||||
export const indexTables = ({ indexes, helpers }) => |
|
||||
indexes.map(i => indexTable(i, helpers)) |
|
||||
|
|
||||
const excludedColumns = ["id", "isNew", "key", "type", "sortKey"] |
|
||||
|
|
||||
export const indexTableProps = (index, helpers) => ({ |
|
||||
data: { |
|
||||
"##bbstate": index.nodeKey(), |
|
||||
"##bbsource": "store", |
|
||||
}, |
|
||||
tableClass: "table table-hover", |
|
||||
theadClass: "thead-dark", |
|
||||
columns: helpers |
|
||||
.indexSchema(index) |
|
||||
.filter(c => !excludedColumns.includes(c.name)) |
|
||||
.map(column), |
|
||||
onRowClick: [ |
|
||||
{ |
|
||||
"##eventHandlerType": "Set State", |
|
||||
parameters: { |
|
||||
path: `selectedrow_${index.name}`, |
|
||||
value: { |
|
||||
"##bbstate": "key", |
|
||||
"##bbsource": "event", |
|
||||
}, |
|
||||
}, |
|
||||
}, |
|
||||
], |
|
||||
}) |
|
||||
|
|
||||
export const getIndexTableName = (index, record) => { |
|
||||
record = record || index.parent().type === "record" ? index.parent() : null |
|
||||
|
|
||||
return record |
|
||||
? `${getRecordPath(record)}/${index.name} Table` |
|
||||
: `${index.name} Table` |
|
||||
} |
|
||||
|
|
||||
const indexTable = (index, helpers) => ({ |
|
||||
name: getIndexTableName(index), |
|
||||
inherits: "@budibase/standard-components/table", |
|
||||
props: indexTableProps(index, helpers), |
|
||||
}) |
|
||||
|
|
||||
const column = col => ({ |
|
||||
title: col.name, |
|
||||
value: { |
|
||||
"##bbstate": col.name, |
|
||||
"##bbsource": "context", |
|
||||
}, |
|
||||
}) |
|
||||
@ -1,183 +0,0 @@ |
|||||
import { getIndexTableName, indexTables } from "./indexTablesGenerator" |
|
||||
|
|
||||
import { buttons } from "./buttonGenerators" |
|
||||
|
|
||||
export const recordHomePageComponents = ({ indexes, records, helpers }) => [ |
|
||||
...recordHomepages({ indexes, records }).map(component), |
|
||||
|
|
||||
...recordHomepages({ indexes, records }).map(homePageButtons), |
|
||||
|
|
||||
...indexTables({ indexes, records, helpers }), |
|
||||
|
|
||||
...buttons({ indexes, buttons, helpers }), |
|
||||
] |
|
||||
|
|
||||
const findIndexForRecord = (indexes, record) => { |
|
||||
const forRecord = indexes.filter(i => |
|
||||
i.allowedRecordNodeIds.includes(record.nodeId) |
|
||||
) |
|
||||
if (forRecord.length === 0) return |
|
||||
if (forRecord.length === 1) return forRecord[0] |
|
||||
const noMap = forRecord.filter(i => !i.filter || !i.filter.trim()) |
|
||||
if (noMap.length === 0) forRecord[0] |
|
||||
return noMap[0] |
|
||||
} |
|
||||
|
|
||||
export const recordHomepages = ({ indexes, records }) => |
|
||||
records |
|
||||
.filter(r => r.parent().type === "root") |
|
||||
.map(r => ({ |
|
||||
record: r, |
|
||||
index: findIndexForRecord(indexes, r), |
|
||||
})) |
|
||||
.filter(r => r.index) |
|
||||
|
|
||||
export const homepageComponentName = record => |
|
||||
`${record.name}/${record.name} homepage` |
|
||||
|
|
||||
const component = ({ record, index }) => ({ |
|
||||
inherits: "@budibase/standard-components/container", |
|
||||
name: homepageComponentName(record), |
|
||||
props: { |
|
||||
className: "d-flex flex-column h-100", |
|
||||
children: [ |
|
||||
{ |
|
||||
component: { |
|
||||
_component: `${record.name}/homepage buttons`, |
|
||||
}, |
|
||||
}, |
|
||||
{ |
|
||||
component: { |
|
||||
_component: getIndexTableName(index), |
|
||||
}, |
|
||||
className: "flex-gow-1 overflow-auto", |
|
||||
}, |
|
||||
], |
|
||||
onLoad: [ |
|
||||
{ |
|
||||
"##eventHandlerType": "Set State", |
|
||||
parameters: { |
|
||||
path: `isEditing${record.name}`, |
|
||||
value: "", |
|
||||
}, |
|
||||
}, |
|
||||
{ |
|
||||
"##eventHandlerType": "List Records", |
|
||||
parameters: { |
|
||||
statePath: index.nodeKey(), |
|
||||
indexKey: index.nodeKey(), |
|
||||
}, |
|
||||
}, |
|
||||
], |
|
||||
}, |
|
||||
}) |
|
||||
|
|
||||
const homePageButtons = ({ index, record }) => ({ |
|
||||
inherits: "@budibase/standard-components/container", |
|
||||
name: `${record.name}/homepage buttons`, |
|
||||
props: { |
|
||||
className: "btn-toolbar mt-4 mb-2", |
|
||||
children: [ |
|
||||
{ |
|
||||
component: { |
|
||||
_component: "@budibase/standard-components/container", |
|
||||
className: "btn-group mr-3", |
|
||||
children: [ |
|
||||
{ |
|
||||
component: { |
|
||||
_component: "common/Default Button", |
|
||||
contentText: `Create ${record.name}`, |
|
||||
onClick: [ |
|
||||
{ |
|
||||
"##eventHandlerType": "Get New Record", |
|
||||
parameters: { |
|
||||
statePath: record.name, |
|
||||
collectionKey: `/${record.collectionName}`, |
|
||||
childRecordType: record.name, |
|
||||
}, |
|
||||
}, |
|
||||
{ |
|
||||
"##eventHandlerType": "Set State", |
|
||||
parameters: { |
|
||||
path: `isEditing${record.name}`, |
|
||||
value: "true", |
|
||||
}, |
|
||||
}, |
|
||||
], |
|
||||
}, |
|
||||
}, |
|
||||
{ |
|
||||
component: { |
|
||||
_component: "common/Default Button", |
|
||||
contentText: `Refresh`, |
|
||||
onClick: [ |
|
||||
{ |
|
||||
"##eventHandlerType": "List Records", |
|
||||
parameters: { |
|
||||
statePath: index.nodeKey(), |
|
||||
indexKey: index.nodeKey(), |
|
||||
}, |
|
||||
}, |
|
||||
], |
|
||||
}, |
|
||||
}, |
|
||||
], |
|
||||
}, |
|
||||
}, |
|
||||
{ |
|
||||
component: { |
|
||||
_component: "@budibase/standard-components/if", |
|
||||
condition: `$store.selectedrow_${index.name} && $store.selectedrow_${index.name}.length > 0`, |
|
||||
thenComponent: { |
|
||||
_component: "@budibase/standard-components/container", |
|
||||
className: "btn-group", |
|
||||
children: [ |
|
||||
{ |
|
||||
component: { |
|
||||
_component: "common/Default Button", |
|
||||
contentText: `Edit ${record.name}`, |
|
||||
onClick: [ |
|
||||
{ |
|
||||
"##eventHandlerType": "Load Record", |
|
||||
parameters: { |
|
||||
statePath: record.name, |
|
||||
recordKey: { |
|
||||
"##bbstate": `selectedrow_${index.name}`, |
|
||||
"##source": "store", |
|
||||
}, |
|
||||
}, |
|
||||
}, |
|
||||
{ |
|
||||
"##eventHandlerType": "Set State", |
|
||||
parameters: { |
|
||||
path: `isEditing${record.name}`, |
|
||||
value: "true", |
|
||||
}, |
|
||||
}, |
|
||||
], |
|
||||
}, |
|
||||
}, |
|
||||
{ |
|
||||
component: { |
|
||||
_component: "common/Default Button", |
|
||||
contentText: `Delete ${record.name}`, |
|
||||
onClick: [ |
|
||||
{ |
|
||||
"##eventHandlerType": "Delete Record", |
|
||||
parameters: { |
|
||||
recordKey: { |
|
||||
"##bbstate": `selectedrow_${index.name}`, |
|
||||
"##source": "store", |
|
||||
}, |
|
||||
}, |
|
||||
}, |
|
||||
], |
|
||||
}, |
|
||||
}, |
|
||||
], |
|
||||
}, |
|
||||
}, |
|
||||
}, |
|
||||
], |
|
||||
}, |
|
||||
}) |
|
||||
@ -1,32 +0,0 @@ |
|||||
import { |
|
||||
recordHomepages, |
|
||||
homepageComponentName, |
|
||||
recordHomePageComponents, |
|
||||
} from "./recordHomePageGenerator" |
|
||||
import { formName, forms } from "./formsGenerator" |
|
||||
|
|
||||
export const selectNavContent = ({ indexes, records, helpers }) => [ |
|
||||
...recordHomepages({ indexes, records }).map(component), |
|
||||
|
|
||||
...recordHomePageComponents({ indexes, records, helpers }), |
|
||||
|
|
||||
...forms({ indexes, records, helpers }), |
|
||||
] |
|
||||
|
|
||||
export const navContentComponentName = record => |
|
||||
`${record.name}/${record.name} Nav Content` |
|
||||
|
|
||||
const component = ({ record }) => ({ |
|
||||
inherits: "@budibase/standard-components/if", |
|
||||
description: `the component that gets displayed when the ${record.collectionName} nav is selected`, |
|
||||
name: navContentComponentName(record), |
|
||||
props: { |
|
||||
condition: `$store.isEditing${record.name}`, |
|
||||
thenComponent: { |
|
||||
_component: formName(record), |
|
||||
}, |
|
||||
elseComponent: { |
|
||||
_component: homepageComponentName(record), |
|
||||
}, |
|
||||
}, |
|
||||
}) |
|
||||
@ -0,0 +1,218 @@ |
|||||
|
<script> |
||||
|
import { splitName } from "./pagesParsing/splitRootComponentName.js" |
||||
|
import { store } from "../builderStore" |
||||
|
import { find, sortBy } from "lodash/fp" |
||||
|
import { ImageIcon, InputIcon, LayoutIcon } from "../common/Icons/" |
||||
|
import Select from "../common/Select.svelte" |
||||
|
import Button from "../common/PlusButton.svelte" |
||||
|
|
||||
|
let componentLibraries = [] |
||||
|
let current_view = "text" |
||||
|
let selectedComponent = null |
||||
|
|
||||
|
const addRootComponent = (component, allComponents) => { |
||||
|
const { libName } = splitName(component.name) |
||||
|
let group = find(r => r.libName === libName)(allComponents) |
||||
|
|
||||
|
if (!group) { |
||||
|
group = { |
||||
|
libName, |
||||
|
components: [], |
||||
|
} |
||||
|
|
||||
|
allComponents.push(group) |
||||
|
} |
||||
|
|
||||
|
group.components.push(component) |
||||
|
} |
||||
|
|
||||
|
const onComponentChosen = store.addChildComponent |
||||
|
|
||||
|
$: { |
||||
|
const newComponentLibraries = [] |
||||
|
|
||||
|
for (let comp of sortBy(["name"])($store.components)) { |
||||
|
addRootComponent(comp, newComponentLibraries) |
||||
|
} |
||||
|
|
||||
|
componentLibraries = newComponentLibraries |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<div class="root"> |
||||
|
<Select> |
||||
|
{#each componentLibraries as componentLibrary} |
||||
|
<option value={componentLibrary.libName}> |
||||
|
{componentLibrary.libName} |
||||
|
</option> |
||||
|
{/each} |
||||
|
</Select> |
||||
|
{#each componentLibraries as componentLibrary} |
||||
|
<div class="library-container"> |
||||
|
<ul> |
||||
|
<li> |
||||
|
<button |
||||
|
class:selected={current_view === 'text'} |
||||
|
on:click={() => (current_view = 'text')}> |
||||
|
<InputIcon /> |
||||
|
</button> |
||||
|
</li> |
||||
|
<li> |
||||
|
<button |
||||
|
class:selected={current_view === 'layout'} |
||||
|
on:click={() => (current_view = 'layout')}> |
||||
|
<LayoutIcon /> |
||||
|
</button> |
||||
|
</li> |
||||
|
<li> |
||||
|
<button |
||||
|
class:selected={current_view === 'media'} |
||||
|
on:click={() => (current_view = 'media')}> |
||||
|
<ImageIcon /> |
||||
|
</button> |
||||
|
</li> |
||||
|
</ul> |
||||
|
|
||||
|
{#each $store.builtins.concat(componentLibrary.components) as component} |
||||
|
<div class="component-container"> |
||||
|
<div |
||||
|
class="component" |
||||
|
on:click={() => onComponentChosen(component.name)}> |
||||
|
<div class="name">{splitName(component.name).componentName}</div> |
||||
|
{#if component.presets && component.name === selectedComponent} |
||||
|
<ul class="preset-menu"> |
||||
|
<span>{splitName(component.name).componentName} Presets</span> |
||||
|
{#each Object.keys(component.presets) as preset} |
||||
|
<li |
||||
|
on:click|stopPropagation={() => onComponentChosen(component.name, preset)}> |
||||
|
{preset} |
||||
|
</li> |
||||
|
{/each} |
||||
|
</ul> |
||||
|
{/if} |
||||
|
</div> |
||||
|
{#if component.presets} |
||||
|
<Button |
||||
|
on:click={() => { |
||||
|
selectedComponent = selectedComponent ? null : component.name |
||||
|
}}> |
||||
|
<span |
||||
|
class="open-presets" |
||||
|
class:open={selectedComponent === component.name}> |
||||
|
... |
||||
|
</span> |
||||
|
</Button> |
||||
|
{/if} |
||||
|
</div> |
||||
|
{/each} |
||||
|
|
||||
|
</div> |
||||
|
{/each} |
||||
|
|
||||
|
</div> |
||||
|
|
||||
|
<style> |
||||
|
.root { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
} |
||||
|
|
||||
|
.library-container { |
||||
|
padding: 0 0 10px 10px; |
||||
|
flex: 1 1 auto; |
||||
|
min-height: 0px; |
||||
|
} |
||||
|
|
||||
|
.component-container { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
} |
||||
|
|
||||
|
.component { |
||||
|
position: relative; |
||||
|
padding: 0 15px; |
||||
|
cursor: pointer; |
||||
|
border: 1px solid #ebebeb; |
||||
|
border-radius: 2px; |
||||
|
margin: 10px 0; |
||||
|
height: 40px; |
||||
|
box-sizing: border-box; |
||||
|
color: #163057; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
flex: 1; |
||||
|
margin-right: 5px; |
||||
|
} |
||||
|
|
||||
|
.component:hover { |
||||
|
background-color: var(--lightslate); |
||||
|
} |
||||
|
|
||||
|
.component > .name { |
||||
|
color: #163057; |
||||
|
display: inline-block; |
||||
|
font-size: 12px; |
||||
|
font-weight: bold; |
||||
|
opacity: 0.6; |
||||
|
} |
||||
|
|
||||
|
ul { |
||||
|
list-style: none; |
||||
|
display: flex; |
||||
|
padding: 0; |
||||
|
} |
||||
|
|
||||
|
.preset-menu { |
||||
|
flex-direction: column; |
||||
|
position: absolute; |
||||
|
top: 25px; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
z-index: 1; |
||||
|
background: #fafafa; |
||||
|
padding: 10px; |
||||
|
border-radius: 2px; |
||||
|
color: rgba(22, 48, 87, 0.6); |
||||
|
} |
||||
|
|
||||
|
.preset-menu > span { |
||||
|
font-size: 12px; |
||||
|
font-weight: bold; |
||||
|
text-transform: uppercase; |
||||
|
} |
||||
|
|
||||
|
.preset-menu li { |
||||
|
font-size: 14px; |
||||
|
margin-top: 13px; |
||||
|
} |
||||
|
|
||||
|
.preset-menu li:hover { |
||||
|
font-weight: bold; |
||||
|
} |
||||
|
|
||||
|
li { |
||||
|
margin-right: 20px; |
||||
|
background: none; |
||||
|
border-radius: 5px; |
||||
|
} |
||||
|
|
||||
|
li button { |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
background: none; |
||||
|
border: none; |
||||
|
border-radius: 5px; |
||||
|
padding: 12px; |
||||
|
outline: none; |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
|
||||
|
.selected { |
||||
|
color: var(--button-text); |
||||
|
background: var(--background-button) !important; |
||||
|
} |
||||
|
|
||||
|
.open { |
||||
|
color: rgba(0, 85, 255, 1); |
||||
|
} |
||||
|
</style> |
||||
@ -1,158 +0,0 @@ |
|||||
<script> |
|
||||
import { splitName } from "./pagesParsing/splitRootComponentName.js" |
|
||||
import { store } from "../builderStore" |
|
||||
import { find, sortBy } from "lodash/fp" |
|
||||
import { ImageIcon, InputIcon, LayoutIcon } from "../common/Icons/" |
|
||||
|
|
||||
let componentLibraries = [] |
|
||||
let current_view = "text" |
|
||||
|
|
||||
const addRootComponent = (c, all) => { |
|
||||
const { libName } = splitName(c.name) |
|
||||
let group = find(r => r.libName === libName)(all) |
|
||||
|
|
||||
if (!group) { |
|
||||
group = { |
|
||||
libName, |
|
||||
components: [], |
|
||||
generators: [], |
|
||||
} |
|
||||
|
|
||||
all.push(group) |
|
||||
} |
|
||||
|
|
||||
group.components.push(c) |
|
||||
} |
|
||||
|
|
||||
const onComponentChosen = store.addChildComponent |
|
||||
|
|
||||
$: { |
|
||||
const newComponentLibraries = [] |
|
||||
|
|
||||
for (let comp of sortBy(["name"])($store.components)) { |
|
||||
addRootComponent(comp, newComponentLibraries) |
|
||||
} |
|
||||
|
|
||||
componentLibraries = newComponentLibraries |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<div class="root"> |
|
||||
{#each componentLibraries as lib} |
|
||||
<div class="library-header">{lib.libName}</div> |
|
||||
|
|
||||
<div class="library-container"> |
|
||||
<ul> |
|
||||
<li> |
|
||||
<button |
|
||||
class:selected={current_view === 'text'} |
|
||||
on:click={() => (current_view = 'text')}> |
|
||||
<InputIcon /> |
|
||||
</button> |
|
||||
</li> |
|
||||
<li> |
|
||||
<button |
|
||||
class:selected={current_view === 'layout'} |
|
||||
on:click={() => (current_view = 'layout')}> |
|
||||
<LayoutIcon /> |
|
||||
</button> |
|
||||
</li> |
|
||||
<li> |
|
||||
<button |
|
||||
class:selected={current_view === 'media'} |
|
||||
on:click={() => (current_view = 'media')}> |
|
||||
<ImageIcon /> |
|
||||
</button> |
|
||||
</li> |
|
||||
</ul> |
|
||||
|
|
||||
{#each $store.builtins.concat(lib.components.filter(_ => true)) as component} |
|
||||
<div |
|
||||
class="component" |
|
||||
on:click={() => onComponentChosen(component.name)}> |
|
||||
<div class="name">{splitName(component.name).componentName}</div> |
|
||||
</div> |
|
||||
{/each} |
|
||||
|
|
||||
</div> |
|
||||
{/each} |
|
||||
|
|
||||
</div> |
|
||||
|
|
||||
<style> |
|
||||
.root { |
|
||||
display: flex; |
|
||||
flex-direction: column; |
|
||||
} |
|
||||
|
|
||||
.library-header { |
|
||||
font-size: 1.1em; |
|
||||
border-color: var(--primary25); |
|
||||
border-width: 1px 0px; |
|
||||
border-style: solid; |
|
||||
background-color: var(--primary10); |
|
||||
padding: 5px 0; |
|
||||
flex: 0 0 auto; |
|
||||
} |
|
||||
|
|
||||
.library-container { |
|
||||
padding: 0 0 10px 10px; |
|
||||
flex: 1 1 auto; |
|
||||
min-height: 0px; |
|
||||
} |
|
||||
|
|
||||
.component { |
|
||||
padding: 0 15px; |
|
||||
cursor: pointer; |
|
||||
border: 1px solid #ccc; |
|
||||
border-radius: 2px; |
|
||||
margin: 10px 0; |
|
||||
height: 40px; |
|
||||
box-sizing: border-box; |
|
||||
color: #163057; |
|
||||
display: flex; |
|
||||
align-items: center; |
|
||||
} |
|
||||
|
|
||||
.component:hover { |
|
||||
background-color: var(--lightslate); |
|
||||
} |
|
||||
|
|
||||
.component > .name { |
|
||||
color: #163057; |
|
||||
display: inline-block; |
|
||||
font-size: 12px; |
|
||||
font-weight: bold; |
|
||||
opacity: 0.6; |
|
||||
} |
|
||||
|
|
||||
ul { |
|
||||
list-style: none; |
|
||||
display: flex; |
|
||||
padding: 0; |
|
||||
} |
|
||||
|
|
||||
li { |
|
||||
margin-right: 20px; |
|
||||
background: none; |
|
||||
border-radius: 5px; |
|
||||
width: 48px; |
|
||||
height: 48px; |
|
||||
} |
|
||||
|
|
||||
li button { |
|
||||
width: 100%; |
|
||||
height: 100%; |
|
||||
background: none; |
|
||||
border: none; |
|
||||
border-radius: 5px; |
|
||||
padding: 12px; |
|
||||
outline: none; |
|
||||
cursor: pointer; |
|
||||
} |
|
||||
|
|
||||
.selected { |
|
||||
color: var(--button-text); |
|
||||
background: var(--background-button) !important; |
|
||||
} |
|
||||
</style> |
|
||||
@ -1,14 +0,0 @@ |
|||||
import resolve from "rollup-plugin-node-resolve" |
|
||||
|
|
||||
export default { |
|
||||
input: "src/generators.js", |
|
||||
output: [ |
|
||||
{ |
|
||||
file: "dist/generators.js", |
|
||||
format: "esm", |
|
||||
name: "budibaseStandardComponents", |
|
||||
sourcemap: "inline", |
|
||||
}, |
|
||||
], |
|
||||
plugins: [resolve()], |
|
||||
} |
|
||||
@ -1,14 +0,0 @@ |
|||||
import resolve from "rollup-plugin-node-resolve" |
|
||||
|
|
||||
export default { |
|
||||
input: "src/generators.js", |
|
||||
output: [ |
|
||||
{ |
|
||||
file: "dist/generators.js", |
|
||||
format: "esm", |
|
||||
name: "budibaseStandardComponents", |
|
||||
sourcemap: "inline", |
|
||||
}, |
|
||||
], |
|
||||
plugins: [resolve()], |
|
||||
} |
|
||||
@ -1,6 +0,0 @@ |
|||||
export { app } from "./generators/appGenerator" |
|
||||
export { forms } from "./generators/formsGenerator" |
|
||||
export { buttons } from "./generators/buttonsGenerator" |
|
||||
export { headers } from "./generators/headersGenerator" |
|
||||
export { nav } from "./generators/navGenerator" |
|
||||
export { indexTables } from "./generators/indexTablesGenerator" |
|
||||
@ -1,6 +0,0 @@ |
|||||
import { forms } from "./formsGenerator" |
|
||||
import { nav } from "./navGenerator" |
|
||||
|
|
||||
export const app = params => { |
|
||||
return [...nav(params), ...forms(params)] |
|
||||
} |
|
||||
@ -1,28 +0,0 @@ |
|||||
export const buttons = () => [ |
|
||||
{ |
|
||||
name: "common/Primary Button", |
|
||||
description: "a styled button", |
|
||||
inherits: "@budibase/standard-components/button", |
|
||||
props: { |
|
||||
padding: "5px 7px", |
|
||||
border: "1px solid #EEE", |
|
||||
color: "#5F6368", |
|
||||
background: "##f2f2f2", |
|
||||
hoverColor: "black", |
|
||||
hoverBackground: "#cccccc", |
|
||||
}, |
|
||||
}, |
|
||||
{ |
|
||||
name: "common/Secondary Button", |
|
||||
description: "a styled button", |
|
||||
inherits: "@budibase/standard-components/button", |
|
||||
props: { |
|
||||
padding: "5px 7px", |
|
||||
border: "1px solid #EEE", |
|
||||
color: "#5F6368", |
|
||||
background: "##f2f2f2", |
|
||||
hoverColor: "black", |
|
||||
hoverBackground: "#cccccc", |
|
||||
}, |
|
||||
}, |
|
||||
] |
|
||||
@ -1,82 +0,0 @@ |
|||||
import { headers } from "./headersGenerator" |
|
||||
|
|
||||
export const forms = ({ records, indexes }) => [ |
|
||||
...headers({ records, indexes }), |
|
||||
...records.map(root), |
|
||||
] |
|
||||
|
|
||||
const root = record => ({ |
|
||||
name: `${record.name} Form`, |
|
||||
description: `All fields on record '${record.nodeKey()}' `, |
|
||||
inherits: "@budibase/standard-components/stackpanel", |
|
||||
props: { |
|
||||
direction: "vertical", |
|
||||
children: [ |
|
||||
{ |
|
||||
control: { |
|
||||
_component: "common/H1", |
|
||||
value: `Edit ${record.name}`, |
|
||||
}, |
|
||||
}, |
|
||||
form(record), |
|
||||
saveCancelButtons(record), |
|
||||
], |
|
||||
}, |
|
||||
}) |
|
||||
|
|
||||
const form = record => ({ |
|
||||
control: { |
|
||||
_component: "@budibase/standard-components/form", |
|
||||
formControls: record.fields.map(f => ({ |
|
||||
label: f.label, |
|
||||
control: { |
|
||||
_component: "@budibase/standard-components/textbox", |
|
||||
value: { |
|
||||
"##bbstate": `current${record.name}.${f.name}`, |
|
||||
"##bbsource": "store", |
|
||||
}, |
|
||||
}, |
|
||||
})), |
|
||||
}, |
|
||||
}) |
|
||||
|
|
||||
const saveCancelButtons = record => ({ |
|
||||
control: { |
|
||||
_component: "@budibase/standard-components/stackpanel", |
|
||||
direction: "horizontal", |
|
||||
children: [ |
|
||||
paddedPanelForButton({ |
|
||||
_component: "common/Primary Button", |
|
||||
contentText: `Save ${record.name}`, |
|
||||
onClick: [ |
|
||||
{ |
|
||||
"##eventHandlerType": "Save Record", |
|
||||
parameters: { |
|
||||
statePath: `current${record.name}`, |
|
||||
}, |
|
||||
}, |
|
||||
], |
|
||||
}), |
|
||||
paddedPanelForButton({ |
|
||||
_component: "common/Secondary Button", |
|
||||
contentText: `Cancel`, |
|
||||
onClick: [ |
|
||||
{ |
|
||||
"##eventHandlerType": "Save Record", |
|
||||
parameters: { |
|
||||
statePath: `current${record.name}`, |
|
||||
}, |
|
||||
}, |
|
||||
], |
|
||||
}), |
|
||||
], |
|
||||
}, |
|
||||
}) |
|
||||
|
|
||||
const paddedPanelForButton = button => ({ |
|
||||
control: { |
|
||||
_component: "@budibase/standard-components/panel", |
|
||||
padding: "20px", |
|
||||
component: button, |
|
||||
}, |
|
||||
}) |
|
||||
@ -1,34 +0,0 @@ |
|||||
export const headers = () => [ |
|
||||
{ |
|
||||
name: "common/H1", |
|
||||
description: "Header 1", |
|
||||
inherits: "@budibase/standard-components/text", |
|
||||
props: { |
|
||||
font: "20pt", |
|
||||
}, |
|
||||
}, |
|
||||
{ |
|
||||
name: "common/H2", |
|
||||
description: "Header 2", |
|
||||
inherits: "@budibase/standard-components/text", |
|
||||
props: { |
|
||||
font: "15pt", |
|
||||
}, |
|
||||
}, |
|
||||
{ |
|
||||
name: "common/H3", |
|
||||
description: "Header 3", |
|
||||
inherits: "@budibase/standard-components/text", |
|
||||
props: { |
|
||||
font: "12pt bold", |
|
||||
}, |
|
||||
}, |
|
||||
{ |
|
||||
name: "common/H4", |
|
||||
description: "Header 4", |
|
||||
inherits: "@budibase/standard-components/text", |
|
||||
props: { |
|
||||
font: "10pt bold", |
|
||||
}, |
|
||||
}, |
|
||||
] |
|
||||
@ -1,26 +0,0 @@ |
|||||
export const indexTables = ({ indexes, helpers }) => |
|
||||
indexes |
|
||||
.filter(i => i.parent().type === "root") |
|
||||
.map(i => indexTable(i, helpers)) |
|
||||
|
|
||||
export const indexTableProps = (index, helpers) => ({ |
|
||||
data: { |
|
||||
"##bbstate": index.nodeKey(), |
|
||||
"##bbsource": "store", |
|
||||
}, |
|
||||
columns: helpers.indexSchema(index).map(column), |
|
||||
}) |
|
||||
|
|
||||
const indexTable = (index, helpers) => ({ |
|
||||
name: `tables/${index.name} Table`, |
|
||||
inherits: "@budibase/standard-components/table", |
|
||||
props: indexTableProps(index, helpers), |
|
||||
}) |
|
||||
|
|
||||
const column = col => ({ |
|
||||
title: col.name, |
|
||||
value: { |
|
||||
"##bbstate": col.name, |
|
||||
"##bbsource": "context", |
|
||||
}, |
|
||||
}) |
|
||||
@ -1,24 +0,0 @@ |
|||||
import { indexTables } from "./indexTablesGenerator" |
|
||||
|
|
||||
export const nav = ({ records, indexes, helpers }) => [ |
|
||||
{ |
|
||||
name: "Application Root", |
|
||||
inherits: "@budibase/standard-components/nav", |
|
||||
props: { |
|
||||
items: indexes.filter(i => i.parent().type === "root").map(navItem), |
|
||||
selectedItem: { |
|
||||
"##bbstate": "selectedNav", |
|
||||
"##bbstatefallback": records[0].collectionName, |
|
||||
"##bbsource": "store", |
|
||||
}, |
|
||||
}, |
|
||||
}, |
|
||||
...indexTables({ records, indexes, helpers }), |
|
||||
] |
|
||||
|
|
||||
export const navItem = index => ({ |
|
||||
title: index.name, |
|
||||
component: { |
|
||||
_component: `tables/${index.name} Table`, |
|
||||
}, |
|
||||
}) |
|
||||
Loading…
Reference in new issue