add drag and drop in the block builder

This commit is contained in:
Simon Vieille 2024-05-13 17:40:05 +02:00
parent 857fcd9897
commit dfbe282d0e
Signed by: deblan
GPG key ID: 579388D585F70417
8 changed files with 89 additions and 107 deletions

View file

@ -17,7 +17,7 @@ class ColumnBlock extends BootstrapBlock
->setLabel('Column')
->setIsContainer(true)
->setOrder(3)
->setClass('col-12 col-md-2 pr-md-1')
->setClass('col-12 col-lg-2 pr-md-1')
->setTemplate('@Core/builder_block/bootstrap/column.html.twig')
->setIcon('<i class="fas fa-columns"></i>')
->addSetting(name: 'size', label: 'Extra small', type: 'number', attributes: ['min' => 0, 'max' => 12])

View file

@ -16,7 +16,7 @@ class ContainerBlock extends BootstrapBlock
->setName('bsContainer')
->setLabel('Container')
->setIsContainer(true)
->setOrder(2)
->setOrder(1)
->setTemplate('@Core/builder_block/bootstrap/container.html.twig')
->setIcon('<i class="fas fa-th"></i>')
->addSetting(name: 'isFluid', label: 'Fluid', type: 'checkbox')

View file

@ -15,7 +15,7 @@ class RowBlock extends BootstrapBlock
$this
->setName('bsRow')
->setLabel('Row')
->setOrder(1)
->setOrder(2)
->setIsContainer(true)
->setIcon('<i class="fas fa-align-justify"></i>')
->setTemplate('@Core/builder_block/bootstrap/row.html.twig')

View file

@ -799,10 +799,17 @@ label.required::after {
.block-settings {
padding: 4px;
margin-bottom: 5px;
}
.block-id {
font-size: 12px;
margin-right: 5px;
}
.block-show-dropzone {
.block-dropzone {
min-height: 40px;
}
}
}

View file

@ -1,15 +1,25 @@
<template>
<div class="block" :key="blockKey" v-if="Object.keys(widgets).length">
<Draggable
v-if="Object.keys(widgets).length"
v-model="value"
:key="blockKey"
:animation="200"
group="children"
ghost-class="ghost"
@start="dragStart"
@end="dragEnd"
handle=".dragger"
:class="{'block-show-dropzone': showDragDrop}"
class="block"
>
<BuilderBlockItem
v-for="(block, key) in value"
:key="block.id + '-' + key"
:item="block"
:widgets="widgets"
:isFirst="key === 0"
:isLast="key == Object.keys(value)[Object.keys(value).length -1]"
@remove-item="removeBlock(key)"
@move-item-up="moveBlockUp(key)"
@move-item-down="moveBlockDown(key)"
@drag-start="dragStart"
@drag-end="dragEnd"
/>
<div class="container">
<BuilderBlockCreate
@ -19,13 +29,14 @@
/>
</div>
<textarea :name="name" class="d-none">{{ toJson(value) }}</textarea>
</div>
</Draggable>
</template>
<script>
import BuilderBlockItem from './BuilderBlockItem'
import BuilderBlockCreate from './BuilderBlockCreate'
import Routing from '../../../../../../../../../friendsofsymfony/jsrouting-bundle/Resources/public/js/router.min.js'
import Draggable from 'vuedraggable'
const axios = require('axios').default
const routes = require('../../../../../../../../../../public/js/fos_js_routes.json')
@ -51,7 +62,8 @@ export default {
return {
value: this.initialValue,
widgets: {},
blockKey: 0
blockKey: 0,
showDragDrop: false,
}
},
methods: {
@ -61,26 +73,6 @@ export default {
triggerBuilderBlockEvent() {
document.querySelector('body').dispatchEvent(new Event('builder_block.update'))
},
moveBlockUp(key) {
let newValue = this.value.map((x) => x)
newValue[key-1] = this.value[key]
newValue[key] = this.value[key-1]
this.value = newValue
++this.blockKey
},
moveBlockDown(key) {
let newValue = this.value.map((x) => x)
newValue[key+1] = this.value[key]
newValue[key] = this.value[key+1]
this.value = newValue
++this.blockKey
},
removeBlock(key) {
let newValue = []
@ -92,12 +84,21 @@ export default {
this.value = newValue
// ++this.blockKey
++this.blockKey
},
dragStart() {
this.showDragDrop = true
},
dragEnd() {
this.showDragDrop = false
++this.blockKey
},
},
components: {
BuilderBlockItem,
BuilderBlockCreate,
Draggable,
},
mounted() {
this.triggerBuilderBlockEvent()

View file

@ -14,7 +14,7 @@
}
.widget {
display: inline-block;
min-width: 100px;
}
.widget-content {
@ -48,22 +48,22 @@
<span class="fa fa-plus"></span>
</span>
<div class="categories mt-2 list-group" :class="{'d-none': !showPicker}">
<div class="categories mt-2" :class="{'d-none': !showPicker}">
<div
v-for="category in categories()"
v-if="Object.keys(category.widgets).length"
class="category"
class="category row"
>
<div
v-if="category.label != 'none'"
v-text="category.label"
class="category-label row"
class="category-label col-12"
></div>
<div
v-for="(widget, name) in category.widgets"
v-on:click="add(name, widget)"
class="widget col-3"
class="widget col-auto"
>
<div class="widget-content">
<div class="widget-label">

View file

@ -22,26 +22,17 @@
>
<span class="fa fa-cog"></span>
</div>
<div
v-if="!isFirst"
v-on:click="moveMeUp"
class="block-header-item block-settings-inverse"
class="block-header-item block-settings-inverse dragger"
>
<span class="fas fa-arrow-up"></span>
</div>
<div
v-if="!isLast"
v-on:click="moveMeDown"
class="block-header-item block-settings-inverse"
>
<span class="fas fa-arrow-down"></span>
<span class="fa fa-arrows-alt"></span>
</div>
</div>
<div class="block-settings" v-if="Object.keys(widget.settings).length" :class="{'d-none': !showSettings}">
<div class="row">
<BuilderBlockSetting
class="mb-0"
v-for="(params, setting) in widget.settings"
:key="item.id + '-' + setting"
:class="widget.class"
@ -52,18 +43,28 @@
</div>
</div>
<BuilderBlockItem
v-if="item.children !== null && item.children.length > 0"
v-for="(child, key) in item.children"
:key="child.id"
:item="child"
:widgets="widgets"
:isFirst="key === 0"
:isLast="key == Object.keys(item.children)[Object.keys(item.children).length -1]"
@remove-item="removeBlock(key)"
@move-item-up="moveBlockUp(key)"
@move-item-down="moveBlockDown(key)"
/>
<Draggable
v-if="widget.isContainer"
v-model="item.children"
ghost-class="ghost"
group="children"
@start="dragStart"
@end="dragEnd"
:animation="200"
handle=".dragger"
class="block-dropzone"
>
<BuilderBlockItem
v-if="item.children !== null && item.children.length > 0"
v-for="(child, key) in item.children"
:key="child.id"
:item="child"
:widgets="widgets"
@remove-item="removeBlock(key)"
@drag-start="dragStart"
@drag-end="dragEnd"
/>
</Draggable>
<div v-if="widget.isContainer" class="container">
<BuilderBlockCreate
@ -78,6 +79,7 @@
<script>
import BuilderBlockCreate from './BuilderBlockCreate'
import BuilderBlockSetting from './BuilderBlockSetting'
import Draggable from 'vuedraggable'
export default {
name: 'BuilderBlockItem',
@ -90,20 +92,12 @@ export default {
type: Object,
required: true
},
isFirst: {
type: Boolean,
required: true
},
isLast: {
type: Boolean,
required: true
}
},
data() {
return {
widget: null,
showSettings: false,
blockKey: 0
blockKey: 0,
}
},
methods: {
@ -113,32 +107,6 @@ export default {
removeMe() {
this.$emit('remove-item')
},
moveMeUp() {
this.$emit('move-item-up')
},
moveMeDown() {
this.$emit('move-item-down')
},
moveBlockUp(key) {
let newValue = this.item.children.map((x) => x)
newValue[key-1] = this.item.children[key]
newValue[key] = this.item.children[key-1]
this.item.children = newValue
++this.blockKey
},
moveBlockDown(key) {
let newValue = this.item.children.map((x) => x)
newValue[key+1] = this.item.children[key]
newValue[key] = this.item.children[key+1]
this.item.children = newValue
++this.blockKey
},
removeBlock(key) {
let children = []
@ -151,10 +119,18 @@ export default {
this.item.children = children
++this.blockKey
},
dragStart() {
this.$emit('drag-start')
},
dragEnd() {
this.$emit('drag-end')
++this.blockKey
},
},
components: {
BuilderBlockCreate,
BuilderBlockSetting,
Draggable,
},
mounted() {
this.widget = this.widgets[this.item.widget]

View file

@ -1,10 +1,6 @@
<template>
<div class="form-group">
<label
v-if="params.label && params.type !== 'checkbox'"
v-text="params.label"
>
</label>
<label class="form-group mb-2">
<span v-if="params.label && params.type !== 'checkbox'" v-text="params.label"></span>
<input
v-if="['number', 'checkbox', 'text'].includes(params.type)"
@ -14,11 +10,7 @@
:class="{'form-control': params.type !== 'checkbox'}"
/>
<label
v-if="params.label && params.type == 'checkbox'"
v-text="params.label"
>
</label>
<span v-if="params.label && params.type == 'checkbox'" v-text="params.label"></span>
<textarea
v-if="params.type == 'textarea'"
@ -37,7 +29,7 @@
{{ v.text }}
</option>
</select>
</div>
</label>
</template>
<script>
@ -59,3 +51,9 @@ export default {
},
}
</script>
<style scoped>
label > span {
margin-bottom: 3px;
}
</style>