GrapesJS Custom Asset Manager
by artur_arseniev
HTML
<script src="https://unpkg.com/grapesjs"></script>
<link rel="stylesheet" href="https://unpkg.com/grapesjs/dist/css/grapes.min.css">
<script src="https://unpkg.com/grapesjs-blocks-basic"></script>
<div id="gjs">
<div style="padding: 25px">Double click on the image below to open the custom Asset Manager</div>
<img src="https://via.placeholder.com/350x250/78c5d6/fff/image1.jpg" />
</div>
<div style="display: none;">
<!-- Vue app for assets -->
<div class="assets-wrp">
<div class="assets">
<div v-for="asset in assets" :key="asset.getSrc()" class="asset" @click="select(asset)" @dblclick="select(asset, true)">
<img class="asset-img" :src="asset.getSrc()" />
<div class="asset-over">
<div>Select</div>
<div class="asset-name">{{ asset.getFilename() }}</div>
</div>
<div class="asset-remove" @click.stop="remove(asset)">Remove</div>
</div>
</div>
</div>
</div>
CSS
body, html {
margin: 0;
height: 100%;
}
.assets-wrp {
margin-top: 15px;
min-height: 300px;
}
.asset-img {
max-width: 100%;
display: block;
}
.asset {
width: 16.66%;
height: 90px;
overflow: hidden;
border-radius: 5px;
margin-bottom: 20px;
cursor: pointer;
position: relative;
}
.assets {
display: flex;
flex-wrap: wrap;
gap: 4.15%;
}
.asset-over {
position: absolute;
width: 100%;
height: 100%;
opacity: 0;
top: 0;
left: 0;
background-color: rgb(0 0 0 / 70%);
transition: opacity 0.3s ease-in-out;
display: flex;
justify-content: flex-end;
align-items: center;
font-size: 12px;
flex-direction: column;
}
.asset-remove {
position: absolute;
top: 0;
right: 0;
padding: 5px;
font-size: 12px;
opacity: 0;
transition: opacity 0.3s ease-in-out;
}
.asset-name {
margin-bottom: 10px;
}
.asset:hover .asset-over,
.asset:hover .asset-remove {
opacity: 1;
}
Babel + JSX
const editor = grapesjs.init({
container: '#gjs',
fromElement: true,
height: '100%',
storageManager: false,
noticeOnUnload: false,
plugins: ['gjs-blocks-basic'],
assetManager: {
custom: true,
assets: [
'https://via.placeholder.com/350x250/78c5d6/fff/image1.jpg',
'https://via.placeholder.com/350x250/459ba8/fff/image2.jpg',
'https://via.placeholder.com/350x250/79c267/fff/image3.jpg',
'https://via.placeholder.com/350x250/c5d647/fff/image4.jpg',
'https://via.placeholder.com/350x250/f28c33/fff/image5.jpg',
'https://via.placeholder.com/350x250/e868a2/fff/image6.jpg',
'https://via.placeholder.com/350x250/cc4360/fff/image7.jpg',
],
},
});
const pagesApp = new Vue({
el: '.assets-wrp',
data: { assets: [] },
mounted() {
editor.on('asset:custom', this.handleAssets);
},
destroyed() {
editor.off('asset:custom', this.handleAssets);
},
methods: {
handleAssets(props) {
props.container.appendChild(this.$el);
this.assets = props.assets;
this.select = props.select;
this.remove = props.remove;
},
}
});