How to use "append" create a structure for a side-menu in the editor and also is it possible to disable a plugin on selection of another one.
Question
[Question]: 1.) I am trying to create a hamburger sidebar for the full-screen view instead of just the mobile view. But when we have dropped the plugin, on dropping any other plugin it is not getting a proper structure on the body to separate the other content and is overlapping. Is there any way to avoid it.
2.) Also on dropping of hamburger side menu, I want the Menu plugin should be disabled. Is there a way to do so.
3.) I would be very helpful if you help it implement it any other way if possible.
For reference: - I have used the menu default plugin and changed a bit to serve my purpose. I am attaching relevant files with respect to the plugin.
**_Index.js_**
`import grapesjs from 'grapesjs';
import loadBlocks from './blocks';
import loadComponents from './components';
import {
hNavbarRef, navbarRef, navbarItemsRef, menuRef
} from './consts';
export default grapesjs.plugins.add('ef-hamburger', (editor, opts = {}) => {
let c = opts;
let defaults = {
blocks: [hNavbarRef],
defaultStyle: 1,
navbarClsPfx: 'navbar',
labelNavbar: 'navbar',
labelNavbarContainer: 'Navbar Container',
labelMenu: 'Navbar Menu',
labelMenuLink: 'Menu link',
labelBurger: 'Burger',
labelBurgerLine: 'Burger Line',
labelNavbarBlock: 'Hamburger',
labelNavbarCategory: 'Extra',
labelHome: 'Home',
labelAbout: 'About',
labelContact: 'Contact',
};
// Load defaults
for (let name in defaults) {
if (!(name in c))
c[name] = defaults[name];
}
loadBlocks(editor, c);
loadComponents(editor, c);
});
`
**_consts.js_**
`export const
hNavbarRef = 'h-navbar',
navbarRef = 'navbar',
navbarItemsRef = 'navbar-items',
menuRef = 'navbar-menu';
`
**_component.js_**
`export default (editor, opt = {}) => {
const c = opt;
const dc = editor.DomComponents;
const defaultType = dc.getType('default');
const defaultModel = defaultType.model;
const burgerType = 'burger-menu';
dc.addType(burgerType, {
model: defaultModel.extend({
defaults: {
...defaultModel.prototype.defaults,
'custom-name': c.labelBurger,
draggable: false,
droppable: false,
copyable: false,
removable: false,
script: function () {
var transEndAdded;
var isAnimating = 0;
var stringCollapse = 'gjs-collapse';
var clickEvent = 'click';
var transitProp = 'max-height';
var transitTiming = 'ease-in-out';
var transitSpeed = 0.25;
var getTransitionEvent = function() {
var t, el = document.createElement('void');
var transitions = {
'transition': 'transitionend',
'OTransition': 'oTransitionEnd',
'MozTransition': 'transitionend',
'WebkitTransition': 'webkitTransitionEnd'
}
for (t in transitions) {
if (el.style[t] !== undefined){
return transitions[t];
}
}
}
var transitEndEvent = getTransitionEvent();
var getElHeight = function(el) {
var style = window.getComputedStyle(el);
var elDisplay = style.display;
var elPos = style.position;
var elVis = style.visibility;
var currentHeight = style.height;
var elMaxHeight = parseInt(style[transitProp]);
if (elDisplay !== 'none' && elMaxHeight !== '0') {
return el.offsetHeight;
}
el.style.height = 'auto';
el.style.display = 'block';
el.style.position = 'absolute';
el.style.visibility = 'hidden';
var height = el.offsetHeight;
el.style.height = '';
el.style.display = '';
el.style.position = '';
el.style.visibility = '';
return height;
};
var toggleSlide = function(el) {
isAnimating = 1;
var elMaxHeight = getElHeight(el);
var elStyle = el.style;
elStyle.display = 'block';
elStyle.transition = transitProp + ' ' + transitSpeed + 's ' + transitTiming;
elStyle.overflowY = 'hidden';
if (elStyle[transitProp] == '') {
elStyle[transitProp] = 0;
}
if (parseInt(elStyle[transitProp]) == 0) {
elStyle[transitProp] = '0';
setTimeout(function() {
elStyle[transitProp] = elMaxHeight + 'px';
}, 10);
} else {
elStyle[transitProp] = '0';
}
}
var toggle = function(e) {
e.preventDefault();
if (isAnimating) {
return;
}
var navParent = this.closest(`[data-gjs=navbar]`);
var navItems = navParent.querySelector(`[data-gjs=navbar-items]`);
toggleSlide(navItems);
if (!transEndAdded) {
navItems.addEventListener(transitEndEvent, function() {
isAnimating = 0;
var itemsStyle = navItems.style;
if (parseInt(itemsStyle[transitProp]) == 0) {
itemsStyle.displatoggleSlidey = '';
itemsStyle[transitProp] = '';
}
});
transEndAdded = 1;
}
};
if ( !(stringCollapse in this ) ) {
this.addEventListener(clickEvent, toggle);
}
this[stringCollapse] = 1;
},
},
}, {
isComponent(el) {
if(el.getAttribute &&
el.getAttribute('data-gjs-type') == burgerType) {
return {type: burgerType};
}
},
}),
view: defaultType.view,
});
}
`
**_blocks.js_**
`import {
hNavbarRef,
navbarRef,
navbarItemsRef,
menuRef
} from "./consts";
export default (editor, opt = {}) => {
const c = opt;
const bm = editor.BlockManager;
const navbarPfx = c.navbarClsPfx || 'navbar';
const style = c.defaultStyle ? `
<style>
body
{
margin: 0;
padding: 0;
// height:auto;
width:auto;
color: black;
font-family: "Avenir Next", "Avenir", sans-serif;
}
a
{
text-decoration: none;
color: #232323;
transition: color 0.3s ease;
}
a:hover
{
color: tomato;
}
#menuToggle
{
display: block;
position: relative;
top: 50px;
left: 50px;
z-index: 1;
background-color: #d1c8c8
-webkit-user-select: none;
user-select: none;
}
#menuToggle input
{
display: block;
width: 40px;
height: 32px;
position: absolute;
top: -7px;
left: -5px;
cursor: pointer;
opacity: 0; /* hide this */
z-index: 2; /* and place it over the hamburger */
-webkit-touch-callout: none;
}
/*
* Just a quick hamburger
*/
#menuToggle span
{
display: block;
width: 33px;
height: 4px;
margin-bottom: 5px;
position: relative;
background: #cdcdcd;
border-radius: 3px;
z-index: 1;
transform-origin: 4px 0px;
transition: transform 0.5s cubic-bezier(0.77,0.2,0.05,1.0),
background 0.5s cubic-bezier(0.77,0.2,0.05,1.0),
opacity 0.55s ease;
}
#menuToggle span:first-child
{
transform-origin: 0% 0%;
}
#menuToggle span:nth-last-child(2)
{
transform-origin: 0% 100%;
}
/*
* Transform all the slices of hamburger
* into a crossmark.
*/
#menuToggle input:checked ~ span
{
opacity: 1;
transform: rotate(45deg) translate(-2px, -1px);
background: #232323;
}
/*
* But let's hide the middle one.
*/
#menuToggle input:checked ~ span:nth-last-child(3)
{
opacity: 0;
transform: rotate(0deg) scale(0.2, 0.2);
}
/*
* Ohyeah and the last one should go the other direction
*/
#menuToggle input:checked ~ span:nth-last-child(2)
{
transform: rotate(-45deg) translate(0, -1px);
}
/*
* Make this absolute positioned
* at the top left of the screen
*/
#menu
{
position: absolute;
width: 150px;
margin: -100px 500px 100px -50px;
padding: 50px;
padding-top: 125px;
height:105vh;
background-color: #d1c8c8;
list-style-type: none;
-webkit-font-smoothing: antialiased;
/* to stop flickering of text in safari */
transform-origin: 0% 0%;
transform: translate(-100%, 0);
transition: transform 0.5s cubic-bezier(0.77,0.2,0.05,1.0);
}
#menu li
{
padding: 10px 0;
font-size: 22px;
}
/*
* And let's slide it in from the left
*/
#menuToggle input:checked ~ ul
{
transform: none;
}
.hamburgercontainer {
width:2em
height:100vh;
}
.full-height {
height: 100vh;
}
</style>
` : '';
bm.add(hNavbarRef, {
label: `
<svg class="gjs-block-svg" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
// <path class="gjs-block-svg-path" d="M22,9 C22,8.4 21.5,8 20.75,8 L3.25,8 C2.5,8 2,8.4 2,9 L2,15 C2,15.6 2.5,16 3.25,16 L20.75,16 C21.5,16 22,15.6 22,15 L22,9 Z M21,15 L3,15 L3,9 L21,9 L21,15 Z" fill-rule="nonzero"></path>
<rect class="gjs-block-svg-path" x="15" y="10" width="5" height="1"></rect>
<rect class="gjs-block-svg-path" x="15" y="10" width="5" height="1"></rect>
<rect class="gjs-block-svg-path" x="15" y="10" width="5" height="1"></rect>
</svg>
<div class="gjs-block-label">${c.labelNavbarBlock}</div>`,
category: 'Event Gadgets',
content: `
<div class = "hamburgercontainer">
<!-- Made by Erik Terwan -->
<!-- 24th of November 2015 -->
<!-- MIT License -->
<div id="menuToggle">
<!--
A fake / hidden checkbox is used as click reciever,
so you can use the :checked selector on it.
-->
<input type="checkbox" />
<!--
Some spans to act as a hamburger.
They are acting like a real hamburger,
not that McDonalds stuff.
-->
<span></span>
<span></span>
<span></span>
<!--
Too bad the menu has to be inside of the button but hey, it's pure CSS magic.
-->
<ul id="menu">
<a href="#"><li>Home</li></a>
<a href="#"><li>About</li></a>
<a href="#"><li>Info</li></a>
<a href="#"><li>Contact</li></a>
</ul>
</div>
</div>
${style}
`,
components:[{
tagName: 'div',
removable: true,
draggable: false,
copyable: true,
droppable:false
}],
});
}
`

Answers (1)
If you need to customize a component read and understand how they work here: https://grapesjs.com/docs/modules/Components.html You have total control over the component in the canvas by using its View
Related Questions and Answers
Continue research with similar issue discussions.
Issue #1504
[Question] Dynamic height
Hi: Is it possible to have an instance of GrapesJS with dynamic height, as in, the editor adjusts to the content size. What I'm trying to d...
Issue #853
[QUESTION] Create Body's trait fixed
I'm trying to create two inputs (width and backgound-color) to template's body and I would like to fix it in Panel's view. When a component...
Issue #3258
QUESTION: Prevent/Disable Custom Blocks from being dropped inside other Custom Blocks
Hello, I have a custom component, let's call it a Section Block. I want to prevent the user from dropping Section Blocks inside other Secti...
Issue #2687
[Question] How to append style manager to custom panel
I would like to append the whole style manager module to a panel? I have been digging up the docs for the past 2 days and couldn't find a p...
Paid Plugins That Match This Issue
Curated by issue keywords and label relevance to help you ship faster.
Loading paid plugin recommendations...
Browse Plugin Categories
Jump directly to plugin category pages on the marketplace.