Add record block layout options (wrap, no wrap)
This commit is contained in:
parent
21740bfec4
commit
a99d90b105
@ -17,7 +17,7 @@
|
||||
>
|
||||
<span
|
||||
:title="label"
|
||||
class="d-inline-block mw-100"
|
||||
class="d-flex"
|
||||
>
|
||||
{{ label }}
|
||||
</span>
|
||||
@ -26,6 +26,7 @@
|
||||
|
||||
<slot name="tools" />
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="small text-muted"
|
||||
:class="{ 'mb-1': description }"
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
>
|
||||
<div
|
||||
v-if="!valueOnly"
|
||||
class="d-flex align-items-center text-primary p-0"
|
||||
class="d-flex align-items-center text-primary px-0"
|
||||
>
|
||||
<span
|
||||
:title="label"
|
||||
@ -48,6 +48,7 @@
|
||||
@input="setMultiValue($event, ctx.index)"
|
||||
/>
|
||||
</multi>
|
||||
|
||||
<template
|
||||
v-else
|
||||
>
|
||||
|
||||
@ -12,7 +12,9 @@
|
||||
|
||||
<div
|
||||
v-else-if="fieldModule"
|
||||
ref="fieldContainer"
|
||||
class="mt-3 px-3"
|
||||
:class="fieldLayoutClass"
|
||||
>
|
||||
<template v-for="field in fields">
|
||||
<b-form-group
|
||||
@ -23,13 +25,14 @@
|
||||
:label-cols-xl="options.horizontalFieldLayoutEnabled && '5'"
|
||||
:content-cols-md="options.horizontalFieldLayoutEnabled && '6'"
|
||||
:content-cols-xl="options.horizontalFieldLayoutEnabled && '7'"
|
||||
class="field-container mb-3"
|
||||
:class="columnWrapClass"
|
||||
:style="fieldWidth"
|
||||
>
|
||||
<template #label>
|
||||
<div
|
||||
class="d-flex text-primary mb-0"
|
||||
>
|
||||
<span class="d-inline-block mw-100">
|
||||
<span class="d-flex">
|
||||
{{ field.label || field.name }}
|
||||
</span>
|
||||
|
||||
@ -108,6 +111,7 @@ import BulkEditModal from 'corteza-webapp-compose/src/components/Public/Record/B
|
||||
import users from 'corteza-webapp-compose/src/mixins/users'
|
||||
import records from 'corteza-webapp-compose/src/mixins/records'
|
||||
import conditionalFields from 'corteza-webapp-compose/src/mixins/conditionalFields'
|
||||
import recordLayout from 'corteza-webapp-compose/src/mixins/recordLayout'
|
||||
|
||||
export default {
|
||||
i18nOptions: {
|
||||
@ -125,6 +129,7 @@ export default {
|
||||
users,
|
||||
records,
|
||||
conditionalFields,
|
||||
recordLayout,
|
||||
],
|
||||
|
||||
data () {
|
||||
@ -160,6 +165,16 @@ export default {
|
||||
})
|
||||
},
|
||||
|
||||
fieldLayoutClass () {
|
||||
const classes = {
|
||||
default: 'd-flex flex-column',
|
||||
noWrap: 'd-flex gap-2',
|
||||
wrap: 'row no-gutters',
|
||||
}
|
||||
|
||||
return classes[this.options.recordFieldLayoutOption]
|
||||
},
|
||||
|
||||
fieldModule () {
|
||||
return this.options.referenceField ? this.referenceModule : this.module
|
||||
},
|
||||
@ -171,6 +186,14 @@ export default {
|
||||
processing () {
|
||||
return !this.fieldRecord || this.evaluating
|
||||
},
|
||||
|
||||
fieldWidth () {
|
||||
if (this.options.recordFieldLayoutOption !== 'noWrap') {
|
||||
return {}
|
||||
}
|
||||
|
||||
return { 'min-width': '13rem' }
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
@ -227,6 +250,29 @@ export default {
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
processing: {
|
||||
handler (newVal) {
|
||||
if (this.options.recordFieldLayoutOption !== 'wrap') return
|
||||
|
||||
if (!newVal && this.fieldModule) {
|
||||
this.$nextTick(() => {
|
||||
this.initializeResizeObserver(this.$refs.fieldContainer, this.options.recordFieldLayoutOption)
|
||||
})
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
'options.recordFieldLayoutOption': {
|
||||
handler (newVal) {
|
||||
if (newVal === 'wrap' && this.fieldModule) {
|
||||
this.initializeResizeObserver(this.$refs.fieldContainer, this.options.recordFieldLayoutOption)
|
||||
} else if (this.resizeObserver) {
|
||||
this.resizeObserver.unobserve(this.$refs.fieldContainer)
|
||||
this.columnWrapClass = ''
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
beforeDestroy () {
|
||||
@ -332,3 +378,10 @@ export default {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.field-col > * {
|
||||
margin-left: 1rem;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
<c-input-checkbox
|
||||
v-model="options.horizontalFieldLayoutEnabled"
|
||||
switch
|
||||
:disabled="options.recordFieldLayoutOption === 'noWrap'"
|
||||
:labels="checkboxLabel"
|
||||
/>
|
||||
</b-form-group>
|
||||
@ -124,6 +125,24 @@
|
||||
/>
|
||||
</b-form-group>
|
||||
</b-col>
|
||||
|
||||
<b-col
|
||||
cols="12"
|
||||
lg="6"
|
||||
>
|
||||
<b-form-group
|
||||
:label="$t('record.fieldsLayoutMode.label')"
|
||||
label-class="text-primary"
|
||||
>
|
||||
<c-input-select
|
||||
v-model="options.recordFieldLayoutOption"
|
||||
:options="recordFieldLayoutOptions"
|
||||
:reduce="option => option.value"
|
||||
:get-option-key="option => option.label"
|
||||
@input="handleRecordFieldLayout"
|
||||
/>
|
||||
</b-form-group>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</div>
|
||||
|
||||
@ -295,6 +314,14 @@ export default {
|
||||
]
|
||||
},
|
||||
|
||||
recordFieldLayoutOptions () {
|
||||
return [
|
||||
{ value: 'default', label: this.$t('record.fieldsLayoutMode.default') },
|
||||
{ value: 'noWrap', label: this.$t('record.fieldsLayoutMode.noWrap') },
|
||||
{ value: 'wrap', label: this.$t('record.fieldsLayoutMode.wrap') },
|
||||
]
|
||||
},
|
||||
|
||||
recordSelectorFields () {
|
||||
return this.module.fields.filter(f => f.kind === 'Record' && !f.isMulti)
|
||||
},
|
||||
@ -374,6 +401,12 @@ export default {
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
handleRecordFieldLayout (v) {
|
||||
if (v !== 'noWrap') return
|
||||
|
||||
this.block.options.horizontalFieldLayoutEnabled = false
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -13,13 +13,16 @@
|
||||
|
||||
<div
|
||||
v-else-if="module"
|
||||
class="mt-3 px-3"
|
||||
ref="fieldContainer"
|
||||
class="mt-3"
|
||||
:class="fieldLayoutClass"
|
||||
>
|
||||
<template v-for="field in fields">
|
||||
<div
|
||||
v-if="canDisplay(field)"
|
||||
:key="field.id"
|
||||
class="field-container mb-3"
|
||||
:class="columnWrapClass"
|
||||
:style="fieldWidth"
|
||||
>
|
||||
<field-editor
|
||||
v-if="isFieldEditable(field)"
|
||||
@ -41,7 +44,9 @@
|
||||
<div
|
||||
class="d-flex align-items-center text-primary mb-0"
|
||||
>
|
||||
<span class="d-inline-block mw-100">
|
||||
<span
|
||||
class="d-flex"
|
||||
>
|
||||
{{ field.label || field.name }}
|
||||
</span>
|
||||
|
||||
@ -90,6 +95,7 @@ import records from 'corteza-webapp-compose/src/mixins/records'
|
||||
import FieldEditor from 'corteza-webapp-compose/src/components/ModuleFields/Editor'
|
||||
import FieldViewer from 'corteza-webapp-compose/src/components/ModuleFields/Viewer'
|
||||
import conditionalFields from 'corteza-webapp-compose/src/mixins/conditionalFields'
|
||||
import recordLayout from 'corteza-webapp-compose/src/mixins/recordLayout'
|
||||
import { debounce } from 'lodash'
|
||||
|
||||
export default {
|
||||
@ -108,6 +114,7 @@ export default {
|
||||
users,
|
||||
records,
|
||||
conditionalFields,
|
||||
recordLayout,
|
||||
],
|
||||
|
||||
props: {
|
||||
@ -137,6 +144,24 @@ export default {
|
||||
})
|
||||
},
|
||||
|
||||
fieldLayoutClass () {
|
||||
const classes = {
|
||||
default: 'd-flex flex-column px-3',
|
||||
noWrap: 'd-flex gap-2 pl-3',
|
||||
wrap: 'row no-gutters',
|
||||
}
|
||||
|
||||
return classes[this.options.recordFieldLayoutOption]
|
||||
},
|
||||
|
||||
fieldWidth () {
|
||||
if (this.options.recordFieldLayoutOption !== 'noWrap') {
|
||||
return {}
|
||||
}
|
||||
|
||||
return { 'min-width': '20rem' }
|
||||
},
|
||||
|
||||
errorID () {
|
||||
const { recordID = NoID } = this.record || {}
|
||||
return recordID === NoID ? 'parent:0' : recordID
|
||||
@ -182,6 +207,25 @@ export default {
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
processing: {
|
||||
handler (newVal) {
|
||||
if (this.options.recordFieldLayoutOption !== 'wrap') return
|
||||
|
||||
if (!newVal && this.module) {
|
||||
this.$nextTick(() => {
|
||||
this.initializeResizeObserver(this.$refs.fieldContainer)
|
||||
})
|
||||
} else if (this.resizeObserver) {
|
||||
this.resizeObserver.unobserve(this.$refs.fieldContainer)
|
||||
this.columnWrapClass = ''
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
beforeDestroy () {
|
||||
this.destroyEvents(this.$refs.fieldContainer)
|
||||
},
|
||||
|
||||
methods: {
|
||||
@ -210,3 +254,10 @@ export default {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.field-col > * {
|
||||
margin-left: 1rem;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
63
client/web/compose/src/mixins/recordLayout.js
Normal file
63
client/web/compose/src/mixins/recordLayout.js
Normal file
@ -0,0 +1,63 @@
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
resizeObserver: null,
|
||||
columnWrapClass: '',
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
initializeResizeObserver (el) {
|
||||
this.resizeObserver = new ResizeObserver((entries) => {
|
||||
for (let entry of entries) {
|
||||
// Handle the resize event here
|
||||
this.applyColumnClasses(entry.contentRect.width)
|
||||
}
|
||||
})
|
||||
|
||||
this.resizeObserver.observe(el)
|
||||
},
|
||||
|
||||
applyColumnClasses (width) {
|
||||
const breakpoints = {
|
||||
xs: 576,
|
||||
md: 768,
|
||||
lg: 992,
|
||||
xl: 1200,
|
||||
}
|
||||
|
||||
const columnClasses = {
|
||||
xs: 'col-12',
|
||||
md: 'col-6',
|
||||
lg: 'col-4',
|
||||
xl: 'col-3',
|
||||
}
|
||||
|
||||
let columnClass
|
||||
|
||||
switch (true) {
|
||||
case width <= breakpoints.xs:
|
||||
columnClass = columnClasses.xs
|
||||
break
|
||||
case width > breakpoints.xs && width <= breakpoints.md:
|
||||
columnClass = columnClasses.md
|
||||
break
|
||||
case width > breakpoints.md && width <= breakpoints.lg:
|
||||
columnClass = columnClasses.lg
|
||||
break
|
||||
default:
|
||||
columnClass = columnClasses.xl
|
||||
break
|
||||
}
|
||||
|
||||
this.columnWrapClass = `field-col ${columnClass}`
|
||||
},
|
||||
|
||||
destroyEvents (el) {
|
||||
if (this.resizeObserver) {
|
||||
this.resizeObserver.unobserve(el)
|
||||
this.resizeObserver.disconnect()
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -19,6 +19,7 @@ interface Options {
|
||||
referenceModuleID?: string;
|
||||
inlineRecordEditEnabled: boolean;
|
||||
horizontalFieldLayoutEnabled: boolean;
|
||||
recordFieldLayoutOption: string;
|
||||
}
|
||||
|
||||
const defaults: Readonly<Options> = Object.freeze({
|
||||
@ -32,6 +33,7 @@ const defaults: Readonly<Options> = Object.freeze({
|
||||
referenceModuleID: undefined,
|
||||
inlineRecordEditEnabled: false,
|
||||
horizontalFieldLayoutEnabled: false,
|
||||
recordFieldLayoutOption: 'default',
|
||||
})
|
||||
|
||||
export class PageBlockRecord extends PageBlock {
|
||||
@ -47,7 +49,7 @@ export class PageBlockRecord extends PageBlock {
|
||||
applyOptions (o?: Partial<Options>): void {
|
||||
if (!o) return
|
||||
|
||||
Apply(this.options, o, String, 'magnifyOption', 'recordSelectorDisplayOption', 'recordSelectorAddRecordDisplayOption', 'referenceField', 'referenceModuleID')
|
||||
Apply(this.options, o, String, 'magnifyOption', 'recordSelectorDisplayOption', 'recordSelectorAddRecordDisplayOption', 'referenceField', 'referenceModuleID', 'recordFieldLayoutOption')
|
||||
Apply(this.options, o, Boolean, 'recordSelectorShowAddRecordButton', 'inlineRecordEditEnabled', 'horizontalFieldLayoutEnabled')
|
||||
|
||||
if (o.fields) {
|
||||
|
||||
@ -278,6 +278,11 @@ record:
|
||||
horizontalFormLayout: Horizontal form layout
|
||||
inlineEdit:
|
||||
enabled: Inline value editing enabled
|
||||
fieldsLayoutMode:
|
||||
label: Fields layout mode
|
||||
default: Default
|
||||
noWrap: No wrap
|
||||
wrap: Wrap
|
||||
preview:
|
||||
blockNoRecord: Cannot render this block without a record
|
||||
fieldsFromModule: Single record block, displaying fields ({{0}}) from module {{1}}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user