Browse Source

Up example ref

pull/5106/head
Artur Arseniev 3 years ago
parent
commit
de4d8e3f42
  1. 359
      docs/modules/Pages.md

359
docs/modules/Pages.md

@ -149,276 +149,133 @@ In the example below you can see an quick implementation of the Page Manager UI.
<!-- Demo template, here for reference <!-- Demo template, here for reference
<style> <style>
.layer-manager { .app-wrap {
position: relative; height: 100%;
text-align: left; width: 100%;
} display: flex;
.layer-item.hidden { }
opacity: 0.5; .editor-wrap {
} widtH: 100%;
.layer-item-icon { height: 100%;
width: 15px; }
cursor: pointer; .pages-wrp, .pages {
} display: flex;
.layer-item-eye { flex-direction: column
} }
.layer-item-chevron { .pages-wrp {
transform: rotate(90deg); background: #333;
} padding: 5px;
.layer-item-chevron.open { }
transform: rotate(180deg); .add-page {
} background: #444444;
.layer-item-chevron.hidden { color: white;
opacity: 0; padding: 5px;
pointer-events: none; border-radius: 2px;
} cursor: pointer;
.layer-item-row { white-space: nowrap;
display: flex; margin-bottom: 10px;
align-items: center; }
user-select: none; .page {
gap: 8px; background-color: #444;
padding: 5px 8px; color: white;
border-bottom: 1px solid rgba(0,0,0,0.35); padding: 5px;
} margin-bottom: 5px;
.layer-item-row.selected { border-radius: 2px;
background-color: rgba(255,255,255,0.15); cursor: pointer;
}
.layer-item-row.hovered { &.selected {
background-color: rgba(255,255,255,0.05); background-color: #706f6f
} }
.layer-item-name { }
margin-left: 3px;
} .page-close {
.layer-item-name.editing { opacity: 0.5;
background-color: white; float: right;
color: #555; background-color: #2c2c2c;
padding: 0 3px; height: 20px;
} display: inline-block;
.layer-item-name-cnt { width: 17px;
display: flex; text-align: center;
align-items: center; border-radius: 3px;
flex-grow: 1;
} &:hover {
.layer-drag-indicator { opacity: 1;
position: absolute; }
width: 100%; }
height: 1px;
left: 0;
background-color: #3b97e3;
}
</style> </style>
<div style="display: none">
<div
class="layer-manager"
@pointerdown="onDragStart"
@pointermove="onDragMove"
@pointerup="onDragEnd"
>
<layer-item v-if="root" :component="root" :level="0"></layer-item>
<div
v-if="dragIndicator.show"
class="layer-drag-indicator"
:style="{ top: `${dragIndicator.y}px`, marginLeft: `${dragIndicator.offset}px`, width: `calc(100% - ${dragIndicator.offset}px)` }"></div>
</div>
<div id="layer-item-template" style="display: none;"> <div style="height: 100%">
<div :class="['layer-item', !visible && 'hidden']"> <div class="app-wrap">
<div <div class="pages-wrp">
:class="['layer-item-row', selected && 'selected', hovered && 'hovered']" <div class="add-page" @click="addPage">Add new page</div>
@click="setSelected" <div class="pages">
@mouseenter="setHover(true)" <div v-for="page in pages" :key="page.id" :class="{page: 1, selected: isSelected(page) }" @click="selectPage(page.id)">
@mouseleave="setHover(false)" {{ page.get('name') || page.id }} <span v-if="!isSelected(page)" @click="removePage(page.id)" class="page-close">&Cross;</span>
ref="layerRef"
data-layer-item
>
<div class="layer-item-icon layer-item-eye" @click.stop="toggleVisibility()">
<svg v-if="visible" viewBox="0 0 24 24"><path fill="currentColor" d="M12,9A3,3 0 0,0 9,12A3,3 0 0,0 12,15A3,3 0 0,0 15,12A3,3 0 0,0 12,9M12,17A5,5 0 0,1 7,12A5,5 0 0,1 12,7A5,5 0 0,1 17,12A5,5 0 0,1 12,17M12,4.5C7,4.5 2.73,7.61 1,12C2.73,16.39 7,19.5 12,19.5C17,19.5 21.27,16.39 23,12C21.27,7.61 17,4.5 12,4.5Z" /></svg>
<svg v-else viewBox="0 0 24 24"><path fill="currentColor" d="M11.83,9L15,12.16C15,12.11 15,12.05 15,12A3,3 0 0,0 12,9C11.94,9 11.89,9 11.83,9M7.53,9.8L9.08,11.35C9.03,11.56 9,11.77 9,12A3,3 0 0,0 12,15C12.22,15 12.44,14.97 12.65,14.92L14.2,16.47C13.53,16.8 12.79,17 12,17A5,5 0 0,1 7,12C7,11.21 7.2,10.47 7.53,9.8M2,4.27L4.28,6.55L4.73,7C3.08,8.3 1.78,10 1,12C2.73,16.39 7,19.5 12,19.5C13.55,19.5 15.03,19.2 16.38,18.66L16.81,19.08L19.73,22L21,20.73L3.27,3M12,7A5,5 0 0,1 17,12C17,12.64 16.87,13.26 16.64,13.82L19.57,16.75C21.07,15.5 22.27,13.86 23,12C21.27,7.61 17,4.5 12,4.5C10.6,4.5 9.26,4.75 8,5.2L10.17,7.35C10.74,7.13 11.35,7 12,7Z" /></svg>
</div>
<div class="layer-item-name-cnt" :style="{ marginLeft: `${level*10}px` }">
<div :class="['layer-item-icon layer-item-chevron', open && 'open', !components.length && 'hidden']" @click.stop="toggleOpen()">
<svg viewBox="0 0 24 24"><path fill="currentColor" d="M7.41,15.41L12,10.83L16.59,15.41L18,14L12,8L6,14L7.41,15.41Z" /></svg>
</div>
<div ref="nameInput"
:class="['layer-item-name', editing && 'editing']"
:contenteditable="editing"
@dblclick.stop="setEditing(true)"
@blur.stop="setEditing(false)"
@keydown.enter="setEditing(false)"
>
{{ name }}
</div> </div>
</div> </div>
<div v-if="component.get('draggable')" class="layer-item-icon layer-item-move" data-layer-move> </div>
<svg viewBox="0 0 24 24"><path fill="currentColor" d="M13,6V11H18V7.75L22.25,12L18,16.25V13H13V18H16.25L12,22.25L7.75,18H11V13H6V16.25L1.75,12L6,7.75V11H11V6H7.75L12,1.75L16.25,6H13Z"/></svg> <div class="editor-wrap">
</div> <div id="gjs"></div>
</div>
<div v-if="open" class="layer-items">
<layer-item v-for="cmp in components" :key="cmp.getId()" :component="cmp" :level="level + 1"/>
</div>
</div> </div>
</div> </div>
</div> </div>
<script> <script>
const { Components, Layers } = editor; const editor = grapesjs.init({
const cmpElMap = new WeakMap(); container: '#gjs',
height: '100%',
Vue.component('layer-item', { storageManager: false,
template: '#layer-item-template', plugins: ['gjs-blocks-basic'],
props: { component: Object, level: Number }, pageManager: {
data() { pages: [{
return { id: 'page-1',
name: '', name: 'Page 1',
components: [], component: '<div id="comp1">Page 1</div>',
visible: true, styles: `#comp1 { color: red }`,
open: false, }, {
selected: false, id: 'page-2',
hovered: false, name: 'Page 2',
editing: false, component: '<div id="comp2">Page 2</div>',
} styles: `#comp2 { color: green }`,
}, }, {
mounted() { id: 'page-3',
this.updateLayer(Layers.getLayerData(this.component)); name: 'Page 3',
cmpElMap.set(this.$refs.layerRef, this.component); component: '<div id="comp3">Page 3</div>',
editor.on('layer:component', this.onLayerComponentUpdate); styles: `#comp3 { color: blue }`,
}, }]
destroyed() {
editor.off('layer:component', this.onLayerComponentUpdate);
}, },
methods: {
onLayerComponentUpdate(cmp) {
if (cmp === this.component) {
this.updateLayer(Layers.getLayerData(cmp));
}
},
updateLayer(data) {
this.name = data.name;
this.components = data.components;
this.visible = data.visible;
this.open = data.open;
this.selected = data.selected;
this.hovered = data.hovered;
},
toggleVisibility() {
const { component } = this;
Layers.setVisible(this.component, !this.visible);
},
toggleOpen() {
const { component } = this;
Layers.setOpen(this.component, !this.open);
},
setHover(hovered) {
Layers.setLayerData(this.component, { hovered })
},
setSelected(event) {
Layers.setLayerData(this.component, { selected: true }, { event })
},
setEditing(value) {
this.editing = value;
const el = this.$refs.nameInput;
if (!value) {
Layers.setName(this.component, el.innerText)
} else {
setTimeout(() => el.focus())
}
},
}
}); });
const pm = editor.Pages;
const app = new Vue({ const app = new Vue({
el: '.layer-manager', el: '.pages-wrp',
data: { data: { pages: [] },
root: null,
isDragging: false,
draggingCmp: null,
draggingOverCmp: null,
dragIndicator: {},
canMoveRes: {},
},
mounted() { mounted() {
editor.on('layer:custom', this.handleCustom); this.setPages(pm.getAll());
editor.on('layer:root', this.handleRootChange); editor.on('page', () => {
}, this.pages = [...pm.getAll()];
destroyed() { });
editor.off('layer:custom', this.handleCustom);
editor.off('layer:root', this.handleRootChange);
}, },
methods: { methods: {
handleCustom(props = {}) { setPages(pages) {
const { container, root } = props; this.pages = [...pages];
container && container.appendChild(this.$el);
this.handleRootChange(root);
},
handleRootChange(root) {
console.log('root update', root);
this.root = root;
}, },
getDragTarget(ev) { isSelected(page) {
const el = document.elementFromPoint(ev.clientX, ev.clientY); return pm.getSelected().id == page.id;
const dragEl = el?.closest('[data-layer-move]');
const elLayer = el?.closest('[data-layer-item]');
return {
dragEl,
elLayer,
cmp: cmpElMap.get(elLayer),
}
}, },
onDragStart(ev) { selectPage(pageId) {
if (this.getDragTarget(ev).dragEl) { return pm.select(pageId);
this.isDragging = true;
}
}, },
onDragMove(ev) { removePage(pageId) {
if (!this.isDragging) return; return pm.remove(pageId);
const { cmp, elLayer } = this.getDragTarget(ev);
if (!cmp || !elLayer) return;
const { draggingCmp } = this;
const layerRect = elLayer.getBoundingClientRect();
const layerH = elLayer.offsetHeight;
const layerY = elLayer.offsetTop;
const pointerY = ev.clientY;
const isBefore = pointerY < (layerRect.y + layerH / 2);
const cmpSource = !draggingCmp ? cmp : draggingCmp;
const cmpTarget = cmp.parent();
const cmpIndex = cmp.index() + (isBefore ? 0 : 1);
this.draggingCmp = !draggingCmp ? cmp : draggingCmp;
this.draggingOverCmp = cmp;
const canMove = Components.canMove(cmpTarget, cmpSource, cmpIndex);
const canMoveInside = Components.canMove(cmp, cmpSource);
const canMoveRes = {
...canMove,
canMoveInside,
index: cmpIndex,
};
// if (
// canMoveInside.result &&
// (
// pointerY > (layerRect.y + LAYER_PAD)
// && pointerY < (layerRect.y + layerH - LAYER_PAD))
// ) {
// pointerInside = true;
// canMoveRes.target = cmp;
// delete canMoveRes.index;
// }
// setDragParent(pointerInside ? cmp : undefined);
this.canMoveRes = canMoveRes;
const dragLevel = (cmp ? cmp.parents() : []).length;
this.dragIndicator = {
y: layerY + (isBefore ? 0 : layerH),
h: layerH,
offset: dragLevel * 10 + 20,
show: !!(this.draggingCmp && canMoveRes?.result),
};
}, },
onDragEnd(ev) { addPage() {
const { canMoveRes } = this; const len = pm.getAll().length;
canMoveRes.result && canMoveRes.source.move(canMoveRes.target, { at: canMoveRes.index }); pm.add({
this.isDragging = false; name: `Page ${len + 1}`,
this.draggingCmp = null; component: '<div>New page</div>',
this.draggingOverCmp = null; });
this.dragIndicator = {};
this.canMoveRes = {};
}, },
} }
}); });

Loading…
Cancel
Save