Adjust tab block style and behaviour
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
<template>
|
||||
<div
|
||||
class="d-flex flex-column align-items-center justify-content-center position-relative h-100"
|
||||
>
|
||||
<div class="d-flex flex-column align-items-center justify-content-center h-100 position-relative">
|
||||
<div
|
||||
v-if="processing"
|
||||
class="d-flex flex-column align-items-center justify-content-center flex-fill"
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
:row-height="50"
|
||||
:is-resizable="!!editable"
|
||||
:is-draggable="!!editable"
|
||||
:responsive="!editable"
|
||||
:cols="columnNumber"
|
||||
:margin="[0, 0]"
|
||||
:responsive="!editable"
|
||||
:use-css-transforms="false"
|
||||
@layout-updated="handleLayoutUpdate"
|
||||
>
|
||||
@@ -23,7 +23,7 @@
|
||||
v-for="(item, index) in gridCollection"
|
||||
>
|
||||
<grid-item
|
||||
v-if="blocks[item.i].meta.tabbed !== true"
|
||||
v-if="!blocks[item.i].meta.hidden"
|
||||
:key="item.i"
|
||||
ref="items"
|
||||
class="grid-item"
|
||||
@@ -161,7 +161,10 @@ export default {
|
||||
deep: true,
|
||||
handler (blocks) {
|
||||
if (blocks.length === 0) this.$emit('change', [])
|
||||
this.grid = blocks.map(({ xywh: [x, y, w, h] }, i) => ({ i, x, y, w, h }))
|
||||
this.grid = blocks.map(({ meta, xywh: [x, y, w, h] }, i) => {
|
||||
// To avoid collision with hidden elements
|
||||
return meta.hidden ? { i, x: 0, y: 0, w: 0, h: 0 } : { i, x, y, w, h }
|
||||
})
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
</div>
|
||||
|
||||
<div
|
||||
ref="cc"
|
||||
:ref="`cc-${blockIndex}`"
|
||||
class="h-100"
|
||||
>
|
||||
<div
|
||||
@@ -87,7 +87,7 @@
|
||||
|
||||
<full-calendar
|
||||
v-show="show && !processing"
|
||||
ref="fc"
|
||||
:ref="`fc-${blockIndex}`"
|
||||
:key="key"
|
||||
:height="getHeight()"
|
||||
:events="events"
|
||||
@@ -259,7 +259,9 @@ export default {
|
||||
|
||||
// Proxy to the FC API
|
||||
api () {
|
||||
return this.$refs.fc.getApi()
|
||||
if (this.$refs[`fc-${this.blockIndex}`]) {
|
||||
return this.$refs[`fc-${this.blockIndex}`].getApi()
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -342,8 +344,8 @@ export default {
|
||||
},
|
||||
|
||||
getHeight () {
|
||||
if (this.$refs.cc) {
|
||||
return this.$refs.cc.clientHeight
|
||||
if (this.$refs[`cc-${this.blockIndex}`]) {
|
||||
return this.$refs[`cc-${this.blockIndex}`].clientHeight
|
||||
}
|
||||
return 'auto'
|
||||
},
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
<vue-select
|
||||
v-model="block.options.chartID"
|
||||
:options="charts"
|
||||
:clearable="true"
|
||||
:placeholder="$t('chart.pick')"
|
||||
:reduce="option => option.chartID"
|
||||
label="name"
|
||||
|
||||
@@ -6,19 +6,10 @@
|
||||
card
|
||||
lazy
|
||||
>
|
||||
<template #tabs-end>
|
||||
<page-translator
|
||||
v-if="page"
|
||||
:page="page"
|
||||
:block.sync="block"
|
||||
:disabled="isNew"
|
||||
button-variant="link"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<b-tab
|
||||
data-test-id="general-tab"
|
||||
active
|
||||
title-item-class="order-first"
|
||||
:title="$t('general.label.general')"
|
||||
>
|
||||
<b-row>
|
||||
@@ -77,6 +68,7 @@
|
||||
<b-col
|
||||
cols="12"
|
||||
sm="6"
|
||||
class="mb-2"
|
||||
>
|
||||
<b-form-group
|
||||
:label="$t('general.headerStyle')"
|
||||
@@ -103,6 +95,14 @@
|
||||
>
|
||||
{{ $t('general.border.show') }}
|
||||
</b-form-checkbox>
|
||||
|
||||
<b-form-checkbox
|
||||
v-if="block.kind !== 'Tabs'"
|
||||
v-model="block.meta.hidden"
|
||||
switch
|
||||
>
|
||||
{{ $t('general.hidden.label') }}
|
||||
</b-form-checkbox>
|
||||
</b-col>
|
||||
|
||||
<b-col
|
||||
@@ -148,19 +148,6 @@
|
||||
/>
|
||||
</b-form-group>
|
||||
</b-col>
|
||||
|
||||
<b-col
|
||||
v-if="showTabOption"
|
||||
cols="12"
|
||||
>
|
||||
<b-form-checkbox
|
||||
v-model="block.meta.tabbed"
|
||||
switch
|
||||
class="mb-2"
|
||||
>
|
||||
{{ $t('general.tabbed.label') }}
|
||||
</b-form-checkbox>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</b-tab>
|
||||
|
||||
@@ -170,6 +157,16 @@
|
||||
class="mh-tab overflow-auto"
|
||||
v-on="$listeners"
|
||||
/>
|
||||
|
||||
<template #tabs-end>
|
||||
<page-translator
|
||||
v-if="page"
|
||||
:page="page"
|
||||
:block.sync="block"
|
||||
:disabled="isNew"
|
||||
button-variant="link"
|
||||
/>
|
||||
</template>
|
||||
</b-tabs>
|
||||
</template>
|
||||
<script>
|
||||
@@ -228,10 +225,6 @@ export default {
|
||||
{ value: 'fullscreen', text: this.$t('general.magnifyOptions.fullscreen') },
|
||||
]
|
||||
},
|
||||
|
||||
showTabOption () {
|
||||
return this.block.kind !== 'Tabs' && this.block.meta !== undefined
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
@@ -9,41 +9,54 @@
|
||||
class="d-flex h-100 align-items-center justify-content-center"
|
||||
>
|
||||
<p class="mb-0">
|
||||
{{ $t('tabs.noTabsBase') }}
|
||||
{{ $t('tabs.noTabs') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<b-tabs
|
||||
v-else
|
||||
v-model="activeTab"
|
||||
nav-wrapper-class="bg-white white border-bottom"
|
||||
card
|
||||
content-class="flex-fill card overflow-hidden"
|
||||
nav-class="bg-white"
|
||||
:nav-wrapper-class="navWrapperClass"
|
||||
:content-class="contentClass"
|
||||
v-bind="{
|
||||
align: block.options.style.alignment,
|
||||
fill: block.options.style.fillJustify === 'fill',
|
||||
justified: block.options.style.fillJustify === 'justified',
|
||||
justified: block.options.style.fillJustify === 'justify',
|
||||
pills: block.options.style.appearance === 'pills',
|
||||
tabs: block.options.style.appearance === 'tabs',
|
||||
small: block.options.style.appearance === 'small',
|
||||
vertical: block.options.style.verticalHorizontal === 'vertical',
|
||||
vertical: block.options.style.orientation === 'vertical',
|
||||
end: block.options.style.position === 'end'
|
||||
}"
|
||||
class="d-flex flex-column h-100"
|
||||
class="h-100"
|
||||
:class="{ 'd-flex flex-column': block.options.style.orientation !== 'vertical' }"
|
||||
>
|
||||
<b-tab
|
||||
v-for="(tab, index) in tabbedBlocks"
|
||||
:key="index"
|
||||
:title="tab.title || tab.block.title || `Block-${tab.block.kind}`"
|
||||
class="h-100 "
|
||||
title-item-class="text-truncate"
|
||||
title-link-class="text-truncate"
|
||||
:key="`${getTabTitle(tab, index)}-${index}`"
|
||||
:title="getTabTitle(tab, index)"
|
||||
class="h-100"
|
||||
:title-item-class="getTitleItemClass(index)"
|
||||
:title-link-class="getTitleItemClass(index)"
|
||||
no-body
|
||||
:lazy="isTabLazy(tab)"
|
||||
>
|
||||
<page-block-tab
|
||||
lazy
|
||||
v-bind="{ ...$attrs, ...$props, page, block: tab.block, blockIndex: index }"
|
||||
v-if="tab.block"
|
||||
v-bind="{ ...$attrs, ...$props, page, block: tab.block, blockIndex: index, boundingRect: { xywh: block.xywh} }"
|
||||
:record="record"
|
||||
:module="module"
|
||||
/>
|
||||
|
||||
<div
|
||||
v-else
|
||||
class="d-flex h-100 align-items-center justify-content-center"
|
||||
>
|
||||
<p class="mb-0">
|
||||
{{ $t('tabs.noBlock') }}
|
||||
</p>
|
||||
</div>
|
||||
</b-tab>
|
||||
</b-tabs>
|
||||
</wrap>
|
||||
@@ -52,7 +65,7 @@
|
||||
<script>
|
||||
import base from './base'
|
||||
import { compose } from '@cortezaproject/corteza-js'
|
||||
import { fetchID } from 'corteza-webapp-compose/src/lib/tabs.js'
|
||||
import { fetchID } from 'corteza-webapp-compose/src/lib/tabs'
|
||||
|
||||
export default {
|
||||
i18nOptions: {
|
||||
@@ -67,21 +80,52 @@ export default {
|
||||
|
||||
extends: base,
|
||||
|
||||
data () {
|
||||
return {
|
||||
activeTab: 0,
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
tabbedBlocks () {
|
||||
return this.block.options.tabs.map(({ blockID, title }) => {
|
||||
const block = this.page.blocks.find(b => fetchID(b) === blockID)
|
||||
return {
|
||||
block: compose.PageBlockMaker(this.page.blocks.find(b => fetchID(b) === blockID)),
|
||||
block: block ? compose.PageBlockMaker(block) : undefined,
|
||||
title,
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
contentClass () {
|
||||
return `card overflow-hidden mh-100 ${this.block.options.style.orientation === 'vertical' ? 'd-block' : 'flex-fill'}`
|
||||
},
|
||||
|
||||
navWrapperClass () {
|
||||
const { orientation, position } = this.block.options.style
|
||||
let border = 'border-bottom'
|
||||
let style = 'bg-white mh-100'
|
||||
|
||||
if (orientation === 'vertical') {
|
||||
border = position === 'end' ? 'border-left' : 'border-right'
|
||||
style = `${style} overflow-auto`
|
||||
} else if (position === 'end') {
|
||||
border = 'border-top'
|
||||
}
|
||||
|
||||
return `${border} ${style}`
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
getTitleItemClass (index) {
|
||||
const { fillJustify, alignment } = this.block.options.style
|
||||
return `order-${index} text-truncate text-${alignment} ${fillJustify !== 'none' ? 'flex-fill' : ''}`
|
||||
},
|
||||
|
||||
getTabTitle ({ title, block = {} }, tabIndex) {
|
||||
const { title: blockTitle, kind } = block
|
||||
return title || blockTitle || kind || `${this.$t('tabs.tab')} ${tabIndex + 1}`
|
||||
},
|
||||
|
||||
isTabLazy ({ block = {} }) {
|
||||
const { kind } = block
|
||||
return ['Calendar', 'Metric', 'Geometry'].includes(kind)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,59 +1,98 @@
|
||||
<template>
|
||||
<b-tab title="Tabs">
|
||||
<div>
|
||||
<h5 class="text-primary">
|
||||
{{ $t('tabs.displayTitle') }}
|
||||
</h5>
|
||||
<b-tab :title="$t('tabs.label')">
|
||||
<h5>
|
||||
{{ $t('tabs.displayTitle') }}
|
||||
</h5>
|
||||
|
||||
<b-row
|
||||
class="mb-3 mt-3 ml-0 mr-0 justify-content-between"
|
||||
no-gutters
|
||||
<b-row
|
||||
class="text-primary"
|
||||
no-gutters
|
||||
>
|
||||
<b-col
|
||||
cols="12"
|
||||
md="4"
|
||||
>
|
||||
<b-form-group label="Appearance">
|
||||
<b-form-group :label="$t('tabs.style.appearance.label')">
|
||||
<b-form-radio-group
|
||||
v-model="block.options.style.appearance"
|
||||
:options="style.appearance"
|
||||
buttons
|
||||
button-variant="outline-primary"
|
||||
size="sm"
|
||||
:options="style.appearance"
|
||||
/>
|
||||
</b-form-group>
|
||||
</b-col>
|
||||
|
||||
<b-form-group label="Alignment">
|
||||
<b-col
|
||||
cols="12"
|
||||
md="4"
|
||||
>
|
||||
<b-form-group :label="$t('tabs.style.orientation.label')">
|
||||
<b-form-radio-group
|
||||
v-model="block.options.style.orientation"
|
||||
:options="style.orientation"
|
||||
buttons
|
||||
button-variant="outline-primary"
|
||||
size="sm"
|
||||
/>
|
||||
</b-form-group>
|
||||
</b-col>
|
||||
|
||||
<b-col
|
||||
cols="12"
|
||||
md="4"
|
||||
>
|
||||
<b-form-group :label="$t('tabs.style.position.label')">
|
||||
<b-form-radio-group
|
||||
v-model="block.options.style.position"
|
||||
:options="style.position"
|
||||
buttons
|
||||
button-variant="outline-primary"
|
||||
size="sm"
|
||||
/>
|
||||
</b-form-group>
|
||||
</b-col>
|
||||
|
||||
<b-col
|
||||
cols="12"
|
||||
md="4"
|
||||
>
|
||||
<b-form-group :label="$t('tabs.style.alignment.label')">
|
||||
<b-form-radio-group
|
||||
v-model="block.options.style.alignment"
|
||||
:options="style.alignment"
|
||||
buttons
|
||||
button-variant="outline-primary"
|
||||
size="sm"
|
||||
:options="style.alignment"
|
||||
/>
|
||||
</b-form-group>
|
||||
<b-form-group label="Fill or Justify">
|
||||
</b-col>
|
||||
|
||||
<b-col
|
||||
cols="12"
|
||||
md="4"
|
||||
>
|
||||
<b-form-group :label="$t('tabs.style.fillJustify.label')">
|
||||
<b-form-radio-group
|
||||
v-model="block.options.style.fillJustify"
|
||||
:options="style.fillJustify"
|
||||
buttons
|
||||
button-variant="outline-primary"
|
||||
size="sm"
|
||||
:options="style.fillJustify"
|
||||
/>
|
||||
</b-form-group>
|
||||
</b-row>
|
||||
</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
|
||||
<div
|
||||
class="d-flex"
|
||||
class="d-flex align-items-center mb-2"
|
||||
>
|
||||
<h5
|
||||
class="font-weight-light m-0 p-0 text-primary"
|
||||
>
|
||||
<h5 class="m-0">
|
||||
{{ $t('tabs.title') }}
|
||||
</h5>
|
||||
|
||||
<b-button
|
||||
variant="link"
|
||||
size="md"
|
||||
:title="shouldDisableAdd ? $t('tabs.tooltip.tabCondition') : $t('tabs.tooltip.addTab')"
|
||||
:disabled="shouldDisableAdd"
|
||||
class="p-0 ml-3 text-decoration-none"
|
||||
@click="addTab"
|
||||
>
|
||||
@@ -63,6 +102,7 @@
|
||||
|
||||
<b-table-simple
|
||||
v-if="block.options.tabs.length"
|
||||
responsive="lg"
|
||||
borderless
|
||||
small
|
||||
>
|
||||
@@ -95,7 +135,7 @@
|
||||
v-for="(tab, index) in block.options.tabs"
|
||||
:key="index"
|
||||
>
|
||||
<b-td class="handle align-middle">
|
||||
<b-td class="handle align-middle pr-2">
|
||||
<font-awesome-icon
|
||||
:icon="['fas', 'bars']"
|
||||
class="grab m-0 text-light p-0"
|
||||
@@ -104,67 +144,66 @@
|
||||
|
||||
<b-td
|
||||
class="align-middle"
|
||||
style="width: 50%"
|
||||
style="width: 50%; min-width: 200px;"
|
||||
>
|
||||
<b-form-input
|
||||
v-model="tab.title"
|
||||
:title="$t('tabs.tooltip.title')"
|
||||
:disabled="!tab.blockID"
|
||||
:placeholder="$t('tabs.form.title')"
|
||||
/>
|
||||
</b-td>
|
||||
|
||||
<b-td
|
||||
class="align-middle"
|
||||
style="width: 50%"
|
||||
style="width: 50%; min-width: 200px;"
|
||||
>
|
||||
<div
|
||||
class="d-flex"
|
||||
>
|
||||
<b-input-group class="d-flex flex-nowrap w-100">
|
||||
<vue-select
|
||||
v-model="tab.blockID"
|
||||
:title="$t('tabs.tooltip.selectBlock')"
|
||||
:options="options"
|
||||
:placeholder="$t('tabs.form.placeholder')"
|
||||
:options="blockOptions"
|
||||
:placeholder="$t('tabs.placeholder.block')"
|
||||
:get-option-label="getBlockLabel"
|
||||
:selectable="option => isSelectable(option)"
|
||||
class="block-selector bg-white m-0"
|
||||
append-to-body
|
||||
style="min-width: 95%;"
|
||||
:reduce="option => option.value"
|
||||
>
|
||||
<template #list-footer>
|
||||
<b-button
|
||||
id="CreateBlockSelectorTab"
|
||||
variant="link"
|
||||
size="sm"
|
||||
:title="$t('tabs.tooltip.newBlock')"
|
||||
class="text-decoration-none"
|
||||
block
|
||||
@click="showBlockSelector(index)"
|
||||
>
|
||||
{{ $t('tabs.addTab') }}
|
||||
</b-button>
|
||||
</template>
|
||||
</vue-select>
|
||||
:calculate-position="calculatePosition"
|
||||
append-to-body
|
||||
class="block-selector bg-white"
|
||||
/>
|
||||
|
||||
<b-button
|
||||
id="popover-edit"
|
||||
size="sm"
|
||||
:disabled="!tab.blockID"
|
||||
:title="$t('tabs.tooltip.edit')"
|
||||
variant="light"
|
||||
@click="editBlock(tab.blockID)"
|
||||
>
|
||||
<font-awesome-icon
|
||||
:icon="['far', 'edit']"
|
||||
/>
|
||||
</b-button>
|
||||
</div>
|
||||
<b-input-group-append>
|
||||
<b-button
|
||||
v-if="tab.blockID"
|
||||
id="popover-edit"
|
||||
size="sm"
|
||||
variant="light"
|
||||
:title="blockEditDisabled ? $t('tabs.tooltip.editDisabled') : $t('tabs.tooltip.edit')"
|
||||
:disabled="blockEditDisabled"
|
||||
class="d-flex align-items-center justify-content-center"
|
||||
style="width: 40px;"
|
||||
@click="editBlock(tab.blockID)"
|
||||
>
|
||||
<font-awesome-icon
|
||||
:icon="['far', 'edit']"
|
||||
/>
|
||||
</b-button>
|
||||
<b-button
|
||||
v-else
|
||||
size="sm"
|
||||
variant="light"
|
||||
:title="$t('tabs.tooltip.addBlock')"
|
||||
class="d-flex align-items-center justify-content-center"
|
||||
style="width: 40px;"
|
||||
@click="showBlockSelector(index)"
|
||||
>
|
||||
<font-awesome-icon
|
||||
:icon="['fas', 'plus']"
|
||||
/>
|
||||
</b-button>
|
||||
</b-input-group-append>
|
||||
</b-input-group>
|
||||
</b-td>
|
||||
|
||||
<td
|
||||
class="text-right align-middle pr-2"
|
||||
style="min-width: 100px;"
|
||||
class="text-center align-middle"
|
||||
style="min-width: 80px;"
|
||||
>
|
||||
<c-input-confirm
|
||||
:title="$t('tabs.tooltip.delete')"
|
||||
@@ -177,7 +216,7 @@
|
||||
|
||||
<div
|
||||
v-else
|
||||
class="text-center pt-5 pb-5"
|
||||
class="text-center my-4"
|
||||
>
|
||||
<p>
|
||||
{{ $t('tabs.noTabs') }}
|
||||
@@ -193,7 +232,7 @@
|
||||
>
|
||||
<new-block-selector
|
||||
:record-page="!!module"
|
||||
:disable-kind="['Tabs']"
|
||||
:disabled-kinds="['Tabs']"
|
||||
@select="addBlock"
|
||||
/>
|
||||
</b-modal>
|
||||
@@ -204,7 +243,8 @@
|
||||
import base from './base'
|
||||
import draggable from 'vuedraggable'
|
||||
import { VueSelect } from 'vue-select'
|
||||
import { fetchID } from 'corteza-webapp-compose/src/lib/tabs.js'
|
||||
import calculatePosition from 'corteza-webapp-compose/src/mixins/vue-select-position'
|
||||
import { fetchID } from 'corteza-webapp-compose/src/lib/tabs'
|
||||
|
||||
export default {
|
||||
i18nOptions: {
|
||||
@@ -222,42 +262,51 @@ export default {
|
||||
|
||||
extends: base,
|
||||
|
||||
mixins: [
|
||||
calculatePosition,
|
||||
],
|
||||
|
||||
data () {
|
||||
return {
|
||||
activeIndex: null,
|
||||
style: {
|
||||
appearance: [
|
||||
{ text: this.$t('tabs.style.appearance.tabs'), value: 'tabs', disabled: false },
|
||||
{ text: this.$t('tabs.style.appearance.pills'), value: 'pills', disabled: false },
|
||||
{ text: this.$t('tabs.style.appearance.small'), value: 'small', disabled: false },
|
||||
{ text: this.$t('tabs.style.appearance.tabs'), value: 'tabs' },
|
||||
{ text: this.$t('tabs.style.appearance.pills'), value: 'pills' },
|
||||
{ text: this.$t('tabs.style.appearance.small'), value: 'small' },
|
||||
],
|
||||
|
||||
alignment: [
|
||||
{ text: this.$t('tabs.style.alignment.left'), value: 'left', disabled: false },
|
||||
{ text: this.$t('tabs.style.alignment.center'), value: 'center', disabled: false },
|
||||
{ text: this.$t('tabs.style.alignment.right'), value: 'right', disabled: false },
|
||||
{ text: this.$t('tabs.style.alignment.left'), value: 'left' },
|
||||
{ text: this.$t('tabs.style.alignment.center'), value: 'center' },
|
||||
{ text: this.$t('tabs.style.alignment.right'), value: 'right' },
|
||||
],
|
||||
|
||||
fillJustify: [
|
||||
{ text: this.$t('tabs.style.fillJustify.fill'), value: 'fill', disabled: false },
|
||||
{ text: this.$t('tabs.style.fillJustify.justified'), value: 'justified', disabled: false },
|
||||
{ text: this.$t('tabs.style.fillJustify.none'), value: 'none', disabled: false },
|
||||
{ text: this.$t('tabs.style.fillJustify.fill'), value: 'fill' },
|
||||
{ text: this.$t('tabs.style.fillJustify.justify'), value: 'justify' },
|
||||
{ text: this.$t('tabs.style.fillJustify.none'), value: 'none' },
|
||||
],
|
||||
|
||||
orientation: [
|
||||
{ text: this.$t('tabs.style.orientation.horizontal'), value: 'horizontal' },
|
||||
{ text: this.$t('tabs.style.orientation.vertical'), value: 'vertical' },
|
||||
],
|
||||
|
||||
position: [
|
||||
{ text: this.$t('tabs.style.position.start'), value: 'start' },
|
||||
{ text: this.$t('tabs.style.position.end'), value: 'end' },
|
||||
],
|
||||
},
|
||||
untabbedBlock: [],
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
|
||||
options () {
|
||||
return this.page.blocks.filter(b => b.kind !== 'Tabs').map((b, i) => {
|
||||
// block title is going to look ugly till you save the page. Inevitable.
|
||||
return { value: fetchID(b), label: b.title || `Block-${b.kind}` }
|
||||
})
|
||||
blockOptions () {
|
||||
return this.page.blocks.filter(b => b.kind !== 'Tabs').map(b => ({ ...b, value: fetchID(b) }))
|
||||
},
|
||||
|
||||
shouldDisableAdd () {
|
||||
blockEditDisabled () {
|
||||
return this.page.blocks.find(b => fetchID(b) === fetchID(this.block)) === undefined
|
||||
},
|
||||
},
|
||||
@@ -271,10 +320,8 @@ export default {
|
||||
},
|
||||
|
||||
methods: {
|
||||
createRequestFulfilled ({ tab }) {
|
||||
if (tab) {
|
||||
this.updateTab(tab, this.activeIndex)
|
||||
}
|
||||
createRequestFulfilled (tab) {
|
||||
this.updateTab(tab, this.activeIndex)
|
||||
},
|
||||
|
||||
addTab () {
|
||||
@@ -299,7 +346,7 @@ export default {
|
||||
|
||||
addBlock (block) {
|
||||
this.$bvModal.hide('createBlockSelectorTab')
|
||||
block.meta.tabbed = true
|
||||
block.meta.hidden = true
|
||||
this.$root.$emit('tab-createRequest', block)
|
||||
},
|
||||
|
||||
@@ -310,22 +357,43 @@ export default {
|
||||
deleteTab (tabIndex) {
|
||||
this.block.options.tabs.splice(tabIndex, 1)
|
||||
},
|
||||
|
||||
getBlockLabel ({ title, kind }) {
|
||||
return title || kind
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.block-selector {
|
||||
position: relative;
|
||||
-ms-flex: 1 1 auto;
|
||||
flex: 1 1 auto;
|
||||
width: 1%;
|
||||
margin-bottom: 0;
|
||||
|
||||
&:not(.vs--open) .vs__selected + .vs__search {
|
||||
// force this to not use any space
|
||||
// we still need it to be rendered for the focus
|
||||
width: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: none;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.vs__selected-options {
|
||||
flex-wrap: nowrap;
|
||||
// do not allow growing
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.vs__selected {
|
||||
max-width: 200px;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,5 +401,4 @@ export default {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="h-100">
|
||||
<b-card
|
||||
no-body
|
||||
class="h-100 shadow"
|
||||
class="h-100 shadow overflow-hidden"
|
||||
:class="blockClass"
|
||||
>
|
||||
<b-card-header
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="h-100">
|
||||
<div
|
||||
class="card bg-transparent h-100"
|
||||
class="card bg-transparent h-100 overflow-hidden"
|
||||
:class="blockClass"
|
||||
>
|
||||
<div
|
||||
|
||||
@@ -14,7 +14,7 @@ export default {
|
||||
scrollableBody: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: () => true,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { NoID } from '@cortezaproject/corteza-js'
|
||||
import { fetchID } from 'corteza-webapp-compose/src/lib/tabs'
|
||||
|
||||
export default {
|
||||
methods: {
|
||||
@@ -46,21 +47,61 @@ export default {
|
||||
newPageTitle = `${this.$t('copyOf')}${this.page.title} (${countDuplicates})`
|
||||
}
|
||||
|
||||
// Change tabbed blockID to use tempID's since they are persisted on save
|
||||
const blocks = page.blocks.map(block => {
|
||||
if (block.kind !== 'Tabs') return block
|
||||
const { tabs = [] } = block.options
|
||||
|
||||
block.options.tabs = tabs.map(b => {
|
||||
const { tempID } = (page.blocks.find(({ blockID }) => blockID === b.blockID) || {}).meta || {}
|
||||
b.blockID = tempID
|
||||
return b
|
||||
})
|
||||
|
||||
return block
|
||||
})
|
||||
|
||||
page = {
|
||||
...page,
|
||||
blocks,
|
||||
pageID: NoID,
|
||||
title: newPageTitle,
|
||||
handle: '',
|
||||
}
|
||||
|
||||
return this.createPage({ namespaceID, ...page })
|
||||
})
|
||||
.then(({ pageID }) => {
|
||||
return this.createPage({ namespaceID, ...page }).then(this.updateTabbedBlockIDs)
|
||||
}).then(({ pageID }) => {
|
||||
this.$router.push({ name: this.$route.name, params: { pageID } })
|
||||
})
|
||||
.catch(this.toastErrorHandler(this.$t('notification:page.cloneFailed')))
|
||||
},
|
||||
|
||||
},
|
||||
async updateTabbedBlockIDs (page) {
|
||||
// get the Tabs Block that still has tabs with tempIDs
|
||||
page.blocks.filter(({ kind }) => kind === 'Tabs')
|
||||
.filter(({ options = {} }) => options.tabs.some(({ blockID }) => (blockID || '').startsWith('tempID-')))
|
||||
.forEach(b => {
|
||||
if (b.kind !== 'Tabs') return
|
||||
|
||||
b.options.tabs.forEach((t, j) => {
|
||||
if (!t.blockID.startsWith('tempID-')) return false
|
||||
|
||||
// find a block with the same tempID that should be updated by now and get its blockID
|
||||
const updatedBlock = page.blocks.find(block => block.meta.tempID === t.blockID)
|
||||
|
||||
if (!updatedBlock) return false
|
||||
|
||||
const tab = {
|
||||
// fetchID gets the blockID using the found block
|
||||
blockID: fetchID(updatedBlock),
|
||||
title: updatedBlock.title,
|
||||
}
|
||||
|
||||
b.options.tabs.splice(j, 1, tab)
|
||||
})
|
||||
})
|
||||
|
||||
return this.updatePage(page)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -108,6 +108,7 @@
|
||||
:icon="['far', 'copy']"
|
||||
/>
|
||||
</b-button>
|
||||
|
||||
<c-input-confirm
|
||||
class="ml-1"
|
||||
size="md"
|
||||
@@ -149,7 +150,7 @@
|
||||
:visible="showCreator"
|
||||
body-class="p-0 border-top-0"
|
||||
header-class="p-3 pb-0 border-bottom-0"
|
||||
@ok="$event => updateBlocks()"
|
||||
@ok="updateBlocks()"
|
||||
@hide="editor = undefined"
|
||||
>
|
||||
<configurator
|
||||
@@ -195,7 +196,6 @@
|
||||
<div>
|
||||
<b-button
|
||||
variant="link"
|
||||
size="md"
|
||||
:title="$t('label.cancel')"
|
||||
class="text-decoration-none"
|
||||
@click="cancel()"
|
||||
@@ -205,7 +205,6 @@
|
||||
|
||||
<b-button
|
||||
variant="primary"
|
||||
size="md"
|
||||
:title="$t('label.saveAndClose')"
|
||||
@click="updateBlocks()"
|
||||
>
|
||||
@@ -221,6 +220,7 @@
|
||||
:hide-delete="hideDelete"
|
||||
:hide-save="!page.canUpdatePage"
|
||||
:disable-clone="disableClone"
|
||||
:disable-save="processing"
|
||||
:clone-tooltip="cloneTooltip"
|
||||
@save="handleSave()"
|
||||
@delete="handleDeletePage"
|
||||
@@ -275,7 +275,7 @@ import PageBlock from 'corteza-webapp-compose/src/components/PageBlocks'
|
||||
import EditorToolbar from 'corteza-webapp-compose/src/components/Admin/EditorToolbar'
|
||||
import { compose, NoID } from '@cortezaproject/corteza-js'
|
||||
import Configurator from 'corteza-webapp-compose/src/components/PageBlocks/Configurator'
|
||||
import { fetchID } from 'corteza-webapp-compose/src/lib/tabs.js'
|
||||
import { fetchID } from 'corteza-webapp-compose/src/lib/tabs'
|
||||
|
||||
export default {
|
||||
i18nOptions: {
|
||||
@@ -309,12 +309,12 @@ export default {
|
||||
|
||||
data () {
|
||||
return {
|
||||
processing: false,
|
||||
|
||||
editor: undefined,
|
||||
page: undefined,
|
||||
blocks: [],
|
||||
board: null,
|
||||
unsavedBlocks: new Set(),
|
||||
id: null,
|
||||
}
|
||||
},
|
||||
|
||||
@@ -501,27 +501,17 @@ export default {
|
||||
},
|
||||
|
||||
deleteBlock (index) {
|
||||
/**
|
||||
* If the block is tabbed, we need to remove it from the tabs when it is deleted.
|
||||
* We find where it is tabbed then remove it from its tabs.
|
||||
* We don't bother checking if it is actually tabbed because you cannot delete a
|
||||
* manually tabed block that is not added to a Tabs block.
|
||||
*/
|
||||
if (this.blocks[index].meta.tabbed) {
|
||||
const whereIsItTabbed = this.blocks.filter((block) => block.kind === 'Tabs' && block.options.tabs.some(({ blockID }) => blockID === fetchID(this.blocks[index])))
|
||||
whereIsItTabbed.forEach((block) => {
|
||||
// If the deleted block is hidden, we need to remove it from the related tabs blocks if it is tabbed.
|
||||
if (this.blocks[index].meta.hidden) {
|
||||
this.blocks.forEach((block) => {
|
||||
if (block.kind !== 'Tabs' || !block.options.tabs.some(({ blockID }) => blockID === fetchID(this.blocks[index]))) return
|
||||
block.options.tabs = block.options.tabs.filter(({ blockID }) => blockID !== fetchID(this.blocks[index]))
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* First we get all the tabs that are tabbed in other Tabs blocks.
|
||||
* The reduce eliminates duplicates as we only need reps of what is tabbed
|
||||
* We check what needs to be freed by comparing allTabs to the tabs of the block
|
||||
* being deleted.
|
||||
*/
|
||||
// Changes meta.hidden property to false, for all blocks that were tabbed only in the deleted block
|
||||
if (this.blocks[index].kind === 'Tabs') {
|
||||
const allTabs = this.blocks.filter((block) => block.kind === 'Tabs' && fetchID(block) !== fetchID(this.blocks[index]))
|
||||
const tabbedBlocks = this.blocks.filter((block) => block.kind === 'Tabs' && fetchID(block) !== fetchID(this.blocks[index]))
|
||||
.map(({ options }) => options.tabs).flat().reduce((unique, o) => {
|
||||
if (!unique.some(tab => tab.blockID === o.blockID)) {
|
||||
unique.push(o)
|
||||
@@ -529,9 +519,12 @@ export default {
|
||||
return unique
|
||||
}, []).map(({ blockID }) => blockID)
|
||||
|
||||
const tobefreed = this.blocks[index].options.tabs.filter(({ blockID }) => !allTabs.includes(blockID))
|
||||
tobefreed.forEach(({ blockID }) => {
|
||||
this.blocks.find((b) => fetchID(b) === blockID).meta.tabbed = false
|
||||
this.blocks[index].options.tabs.forEach(({ blockID }) => {
|
||||
if (tabbedBlocks.includes(blockID)) return
|
||||
const index = this.blocks.findIndex((b) => fetchID(b) === blockID)
|
||||
if (index === -1) return
|
||||
this.blocks[index].meta.hidden = false
|
||||
this.calculateNewBlockPosition(this.blocks[index])
|
||||
})
|
||||
}
|
||||
|
||||
@@ -550,10 +543,6 @@ export default {
|
||||
this.unsavedBlocks.add(index)
|
||||
},
|
||||
|
||||
generateUID () {
|
||||
return Math.random().toString(36).substring(2) + (new Date()).getTime().toString(36)
|
||||
},
|
||||
|
||||
updateBlocks (block = this.editor.block) {
|
||||
block = compose.PageBlockMaker(block)
|
||||
this.page.blocks = this.blocks
|
||||
@@ -561,17 +550,17 @@ export default {
|
||||
if (this.editor.index !== undefined) {
|
||||
const oldBlock = this.blocks[this.editor.index]
|
||||
|
||||
if (oldBlock.meta.tabbed === true && this.editor.block.meta.tabbed === false) {
|
||||
if (oldBlock.meta.hidden === true && this.editor.block.meta.hidden === false) {
|
||||
this.untabBlock(this.editor.block)
|
||||
this.calculateNewBlockPosition(block)
|
||||
}
|
||||
|
||||
if (this.editor.block.kind !== block.kind) {
|
||||
this.page.blocks.push(block)
|
||||
const tab = {
|
||||
this.$root.$emit('builder-createRequestFulfilled', {
|
||||
blockID: fetchID(block),
|
||||
title: block.title,
|
||||
}
|
||||
this.$root.$emit('builder-createRequestFulfilled', { tab })
|
||||
})
|
||||
} else {
|
||||
this.page.blocks.splice(this.editor.index, 1, block)
|
||||
this.unsavedBlocks.add(this.editor.index)
|
||||
@@ -582,9 +571,9 @@ export default {
|
||||
}
|
||||
|
||||
if (block.kind === 'Tabs') {
|
||||
block.options.tabs = block.options.tabs.filter(t => t.blockID !== null)
|
||||
block.options.tabs.forEach((tab) => {
|
||||
this.page.blocks.find(b => fetchID(b) === tab.blockID).meta.tabbed = true
|
||||
if (!tab.blockID) return
|
||||
this.page.blocks.find(b => fetchID(b) === tab.blockID).meta.hidden = true
|
||||
})
|
||||
}
|
||||
|
||||
@@ -594,20 +583,15 @@ export default {
|
||||
},
|
||||
|
||||
cloneBlock (index) {
|
||||
this.appendBlock({ ...this.blocks[index].clone() }, this.$t('notification:page.cloneSuccess'))
|
||||
this.appendBlock(this.blocks[index].clone(), this.$t('notification:page.cloneSuccess'))
|
||||
},
|
||||
|
||||
appendBlock (block, msg) {
|
||||
if (this.blocks.length) {
|
||||
// ensuring we append the block to the end of the page
|
||||
// eslint-disable-next-line
|
||||
const maxY = this.blocks.map((block) => block.xywh[1]).reduce((acc, val) => {
|
||||
return acc > val ? acc : val
|
||||
}, 0)
|
||||
block.xywh = [0, maxY + 2, 3, 3]
|
||||
}
|
||||
this.calculateNewBlockPosition(block)
|
||||
|
||||
this.editor = { index: undefined, block: compose.PageBlockMaker(block) }
|
||||
this.updateBlocks()
|
||||
|
||||
if (!this.editor) {
|
||||
msg && this.toastSuccess(msg)
|
||||
return true
|
||||
@@ -617,6 +601,17 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
calculateNewBlockPosition (block) {
|
||||
if (this.blocks.length) {
|
||||
// ensuring we append the block to the end of the page
|
||||
// eslint-disable-next-line
|
||||
const maxY = this.blocks.filter(({ meta }) => !meta.hidden).map((block) => block.xywh[1]).reduce((acc, val) => {
|
||||
return acc > val ? acc : val
|
||||
}, 0)
|
||||
block.xywh = [0, maxY + 2, 3, 3]
|
||||
}
|
||||
},
|
||||
|
||||
async handleSave ({ closeOnSuccess = false, previewOnSuccess = false } = {}) {
|
||||
const { namespaceID } = this.namespace
|
||||
|
||||
@@ -645,48 +640,27 @@ export default {
|
||||
return
|
||||
}
|
||||
|
||||
this.processing = true
|
||||
|
||||
this.findPageByID({ namespaceID, pageID: this.pageID, force: true })
|
||||
.then(page => {
|
||||
// Merge changes
|
||||
const mergedPage = new compose.Page({ namespaceID, ...page, blocks: this.blocks })
|
||||
|
||||
this.updatePage(mergedPage).then((page) => {
|
||||
// get the Tabs Block that still has tabs with tempIDs
|
||||
const tabsWithTempIDs = this.page.blocks.filter(b => b.kind === 'Tabs').filter(b => b.options.tabs.some(t => t.blockID.startsWith('tempID-')))
|
||||
|
||||
if (!tabsWithTempIDs.length) return page
|
||||
|
||||
page.blocks.forEach(b => {
|
||||
if (b.kind !== 'Tabs') return
|
||||
|
||||
tabsWithTempIDs.find(t => t.meta.tempID === b.meta.tempID).options.tabs.forEach((t, j) => {
|
||||
if (!t.blockID.startsWith('tempID-')) return false
|
||||
|
||||
// find a block with the same tempID that should be updated by now and get its blockID
|
||||
const updatedBlock = page.blocks.find(block => block.meta.tempID === t.blockID)
|
||||
|
||||
if (!updatedBlock) return false
|
||||
|
||||
const tab = {
|
||||
// fetchID gets the blockID using the found block
|
||||
blockID: fetchID(updatedBlock),
|
||||
title: updatedBlock.title,
|
||||
}
|
||||
b.options.tabs.splice(j, 1, tab)
|
||||
})
|
||||
})
|
||||
return this.updatePage(page)
|
||||
}).then((page) => {
|
||||
this.unsavedBlocks.clear()
|
||||
this.toastSuccess(this.$t('notification:page.saved'))
|
||||
if (closeOnSuccess) {
|
||||
this.$router.push({ name: 'admin.pages' })
|
||||
} else if (previewOnSuccess) {
|
||||
this.$router.push({ name: 'page', params: { pageID: this.pageID } })
|
||||
}
|
||||
this.page = new compose.Page(page)
|
||||
}).catch(this.toastErrorHandler(this.$t('notification:page.saveFailed')))
|
||||
return this.updatePage(mergedPage).then(this.updateTabbedBlockIDs)
|
||||
}).then((page) => {
|
||||
this.unsavedBlocks.clear()
|
||||
this.toastSuccess(this.$t('notification:page.saved'))
|
||||
if (closeOnSuccess) {
|
||||
this.$router.push({ name: 'admin.pages' })
|
||||
} else if (previewOnSuccess) {
|
||||
this.$router.push({ name: 'page', params: { pageID: this.pageID } })
|
||||
}
|
||||
this.page = new compose.Page(page)
|
||||
}).finally(() => {
|
||||
this.processing = false
|
||||
})
|
||||
.catch(this.toastErrorHandler(this.$t('notification:page.saveFailed')))
|
||||
},
|
||||
|
||||
validateModuleFieldSelection (module, page) {
|
||||
@@ -734,8 +708,20 @@ export default {
|
||||
},
|
||||
|
||||
async copyBlock (index) {
|
||||
const parsedBlock = JSON.stringify(this.blocks[index].clone())
|
||||
navigator.clipboard.writeText(parsedBlock).then(() => {
|
||||
const block = JSON.stringify(this.blocks[index].clone())
|
||||
|
||||
// Change tabbed blockID to use tempID's since they are persisted on save
|
||||
if (block.kind === 'Tabs') {
|
||||
const { tabs = [] } = block.options
|
||||
|
||||
block.options.tabs = tabs.map(b => {
|
||||
const { tempID } = (this.blocks.find(({ blockID }) => blockID === b.blockID) || {}).meta || {}
|
||||
b.blockID = tempID
|
||||
return b
|
||||
})
|
||||
}
|
||||
|
||||
navigator.clipboard.writeText(block).then(() => {
|
||||
this.toastSuccess(this.$t('notification:page.copySuccess'))
|
||||
this.toastInfo(this.$t('notification:page.blockWaiting'))
|
||||
this.$refs.pageBuilder.focus()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { merge } from 'lodash'
|
||||
import { Apply } from '../../../cast'
|
||||
import { Apply, NoID } from '../../../cast'
|
||||
import { generateUID } from '../../helpers/idgen'
|
||||
import { PageBlockMaker } from './'
|
||||
|
||||
interface PageBlockStyleVariants {
|
||||
[_: string]: string;
|
||||
@@ -21,7 +22,7 @@ interface PageBlockStyle {
|
||||
}
|
||||
|
||||
interface PageBlockMeta {
|
||||
tabbed?: boolean;
|
||||
hidden?: boolean;
|
||||
tempID?: string;
|
||||
}
|
||||
|
||||
@@ -41,7 +42,7 @@ export class PageBlock {
|
||||
public options = {}
|
||||
|
||||
public meta: PageBlockMeta = {
|
||||
tabbed: false,
|
||||
hidden: false,
|
||||
tempID: undefined,
|
||||
}
|
||||
|
||||
@@ -102,13 +103,8 @@ export class PageBlock {
|
||||
this.meta.tempID = this.meta.tempID || generateUID()
|
||||
}
|
||||
|
||||
clone(): PageBlockInput {
|
||||
const clone = new PageBlock()
|
||||
clone.kind = this.kind
|
||||
clone.title = this.title
|
||||
clone.style = merge({}, this.style)
|
||||
clone.options = merge({}, this.options)
|
||||
return clone
|
||||
clone (): PageBlockInput {
|
||||
return PageBlockMaker({ ...this, blockID: NoID, meta: { tempID: '' } })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ class CalendarOptions {
|
||||
public feeds: Array<Feed> = []
|
||||
public header: Partial<CalendarOptionsHeader> = {}
|
||||
public locale = 'en-gb'
|
||||
public tabbed = false
|
||||
public refreshRate = 0
|
||||
public showRefresh = false
|
||||
public magnifyOption = ''
|
||||
@@ -76,7 +75,6 @@ export class PageBlockCalendar extends PageBlock {
|
||||
)
|
||||
|
||||
this.options.locale = o.locale || 'en-gb'
|
||||
this.options.tabbed = o.tabbed || false
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,14 +17,14 @@ interface Options {
|
||||
}
|
||||
|
||||
const defaults: Readonly<Options> = Object.freeze({
|
||||
chartID: NoID,
|
||||
chartID: '',
|
||||
refreshRate: 0,
|
||||
showRefresh: false,
|
||||
magnifyOption: '',
|
||||
drillDown: {
|
||||
enabled: false,
|
||||
blockID: '',
|
||||
},
|
||||
blockID: ''
|
||||
}
|
||||
})
|
||||
|
||||
export class PageBlockChart extends PageBlock {
|
||||
|
||||
@@ -19,7 +19,7 @@ export { PageBlockNavigation } from './navigation'
|
||||
export { PageBlockTab } from './tabs'
|
||||
export { PageBlockGeometry } from './geometry'
|
||||
|
||||
export function PageBlockMaker<T extends PageBlock>(i: { kind: string }): T {
|
||||
export function PageBlockMaker<T extends PageBlock> (i: { kind: string }): T {
|
||||
const PageBlockTemp = Registry.get(i.kind)
|
||||
if (PageBlockTemp === undefined) {
|
||||
throw new Error(`unknown block kind '${i.kind}'`)
|
||||
|
||||
@@ -103,7 +103,7 @@ export class PageBlockProgress extends PageBlock {
|
||||
}
|
||||
|
||||
if (o.display) {
|
||||
this.options.display = o.display
|
||||
this.options.display = { ...this.options.display, ...o.display }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ interface Options {
|
||||
|
||||
// referenced fields (records, users) we want to expand
|
||||
expRefFields: string[];
|
||||
|
||||
refreshRate: number;
|
||||
showRefresh: boolean;
|
||||
magnifyOption: string;
|
||||
|
||||
@@ -6,6 +6,8 @@ interface Style {
|
||||
appearance: string;
|
||||
alignment: string;
|
||||
fillJustify: string;
|
||||
orientation: string;
|
||||
position: string;
|
||||
}
|
||||
|
||||
interface Tab {
|
||||
@@ -21,8 +23,10 @@ interface Options {
|
||||
const defaults: Readonly<Options> = Object.freeze({
|
||||
style: {
|
||||
appearance: 'tabs',
|
||||
alignment: 'left',
|
||||
fillJustify: 'none',
|
||||
alignment: 'center',
|
||||
fillJustify: 'justify',
|
||||
orientation: 'horizontal',
|
||||
position: 'start',
|
||||
},
|
||||
tabs: [],
|
||||
})
|
||||
@@ -45,7 +49,7 @@ export class PageBlockTab extends PageBlock {
|
||||
}
|
||||
|
||||
if (o.style) {
|
||||
this.options.style = o.style
|
||||
this.options.style = { ...this.options.style, ...o.style }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,8 +123,8 @@ general:
|
||||
modal: Modal
|
||||
fullscreen: Fullscreen
|
||||
wrap: Display block as a card
|
||||
tabbed:
|
||||
label: Tabbed
|
||||
hidden:
|
||||
label: Hidden
|
||||
refresh:
|
||||
label: Refresh
|
||||
auto: Auto refresh
|
||||
@@ -701,34 +701,39 @@ tabs:
|
||||
alertTitle: Set a title for your block
|
||||
title: Tabs
|
||||
addTab: + Add
|
||||
tab: Tab
|
||||
selectBlock: Choose a block
|
||||
noTabs: No tabs have been made
|
||||
noTabsBase: No tabs have been made yet
|
||||
noTabs: No tabs configured
|
||||
noBlock: No block configured
|
||||
displayTitle: Display Options
|
||||
preview: Live example
|
||||
newBlockModal: Add new block
|
||||
form:
|
||||
title: Set a title for your tab
|
||||
placeholder: Tab a block
|
||||
placeholder:
|
||||
block: Select a block to tab
|
||||
style:
|
||||
appearance:
|
||||
label: Appearance
|
||||
tabs: Tabs
|
||||
pills: Pills
|
||||
small: Small
|
||||
alignment:
|
||||
label: Alignment
|
||||
left: Left
|
||||
center: Center
|
||||
right: Right
|
||||
fillJustify:
|
||||
label: Fill or Justify
|
||||
fill: Fill
|
||||
justified: Justify
|
||||
justify: Justify
|
||||
none: None
|
||||
verticalHorizontal:
|
||||
orientation:
|
||||
label: Orientation
|
||||
vertical: Vertical
|
||||
horizontal: Horizontal
|
||||
tabPosition:
|
||||
top: Top
|
||||
bottom: Bottom
|
||||
position:
|
||||
label: Position
|
||||
start: Start
|
||||
end: End
|
||||
table:
|
||||
columns:
|
||||
title:
|
||||
@@ -737,13 +742,8 @@ tabs:
|
||||
label: Block
|
||||
tooltip:
|
||||
edit: Edit block
|
||||
changeTab: Change tab
|
||||
editDisabled: Editing tabbed blocks is disabled until you save this block
|
||||
addTab: Add tab
|
||||
cancel: Switch to view mode
|
||||
newBlock: Add new block
|
||||
addBlock: Add new block
|
||||
delete: Delete tab
|
||||
selectBlock: Select a block to tab
|
||||
move: Move tab
|
||||
title: Tab title
|
||||
tabCondition: You can't make tabs until you add this block
|
||||
label: Tabs
|
||||
|
||||
Reference in New Issue
Block a user