├── .gitignore ├── README.md ├── composer.json ├── dist ├── css │ └── field.css ├── fonts │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ ├── fontawesome-webfont.woff2 │ ├── main-fonts.eot │ ├── main-fonts.svg │ ├── main-fonts.ttf │ └── main-fonts.woff ├── js │ └── field.js └── mix-manifest.json ├── package.json ├── resources ├── css │ ├── demos.css │ ├── grapes-code-editor.min.css │ ├── grapes.min.css │ ├── grapesjs-plugin-filestack.css │ ├── grapesjs-preset-webpage.min.css │ ├── toastr.min.css │ └── tooltip.css ├── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ ├── fontawesome-webfont.woff2 │ ├── main-fonts.eot │ ├── main-fonts.svg │ ├── main-fonts.ttf │ └── main-fonts.woff ├── js │ ├── components │ │ ├── DetailField.vue │ │ └── FormField.vue │ ├── field.js │ └── plugins │ │ └── custom.js └── sass │ └── field.scss ├── src ├── FieldServiceProvider.php └── PageBuilderField.php └── webpack.mix.js /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /vendor 3 | /node_modules 4 | package-lock.json 5 | composer.phar 6 | composer.lock 7 | phpunit.xml 8 | .phpunit.result.cache 9 | .DS_Store 10 | Thumbs.db 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nova PageBuilder Field. 2 | 3 | This field allows you to build custom styled web pages, using https://github.com/artf/grapesjs 4 | 5 | ## Installation 6 | 7 | You can install the package via composer: 8 | 9 | ```bash 10 | composer require digitalcloud/nova-page-builder-field 11 | ``` 12 | 13 | You can publish the required assets with: 14 | 15 | ```shell 16 | php artisan vendor:publish --provider="DigitalCloud\PageBuilderField\FieldServiceProvider" --tag=public 17 | ``` 18 | 19 | ## Usage 20 | 21 | ```php 22 | use use DigitalCloud\PageBuilderField\PageBuilderField; 23 | // .... 24 | 25 | PageBuilderField::make('page'), 26 | 27 | ``` 28 | 29 | ## Images 30 | Form field 31 | ![gjs-form](https://user-images.githubusercontent.com/41853913/49926239-d62ab100-fec3-11e8-8433-8b5b2db59bb0.PNG) 32 | 33 | Detail field 34 | ![gjs-view](https://user-images.githubusercontent.com/41853913/49926241-d6c34780-fec3-11e8-872b-75d1af080288.PNG) 35 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "digitalcloud/nova-page-builder-field", 3 | "description": "A Laravel Nova page builder field.", 4 | "keywords": [ 5 | "laravel", 6 | "nova", 7 | "field", 8 | "page builder", 9 | "page design" 10 | ], 11 | "license": "MIT", 12 | "require": { 13 | "php": ">=7.1.0" 14 | }, 15 | "autoload": { 16 | "psr-4": { 17 | "DigitalCloud\\PageBuilderField\\": "src/" 18 | } 19 | }, 20 | "extra": { 21 | "laravel": { 22 | "providers": [ 23 | "DigitalCloud\\PageBuilderField\\FieldServiceProvider" 24 | ] 25 | } 26 | }, 27 | "config": { 28 | "sort-packages": true 29 | }, 30 | "minimum-stability": "dev", 31 | "prefer-stable": true 32 | } 33 | -------------------------------------------------------------------------------- /dist/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DigitalCloud/nova-page-builder-field/19e2460c3de232592511d55176ddee71a5ad5947/dist/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /dist/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DigitalCloud/nova-page-builder-field/19e2460c3de232592511d55176ddee71a5ad5947/dist/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /dist/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DigitalCloud/nova-page-builder-field/19e2460c3de232592511d55176ddee71a5ad5947/dist/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /dist/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DigitalCloud/nova-page-builder-field/19e2460c3de232592511d55176ddee71a5ad5947/dist/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /dist/fonts/main-fonts.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DigitalCloud/nova-page-builder-field/19e2460c3de232592511d55176ddee71a5ad5947/dist/fonts/main-fonts.eot -------------------------------------------------------------------------------- /dist/fonts/main-fonts.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 29 | 34 | 35 | 42 | 51 | 55 | 58 | 63 | 68 | 73 | 78 | 83 | 88 | 93 | 98 | 103 | 108 | 113 | 118 | 123 | 128 | 133 | 138 | 143 | 148 | 153 | 154 | 155 | 186 | 196 | 197 | 199 | 200 | 202 | image/svg+xml 203 | 205 | 206 | 207 | 208 | 209 | 214 | 219 | 224 | 229 | 234 | 240 | 245 | 248 | 253 | 254 | 269 | 285 | 290 | Borders: 30pxCanvas: 1000x1000px 308 | 312 | 315 | 317 | 321 | 325 | 329 | 333 | 337 | 341 | 345 | 349 | 350 | 351 | 352 | 353 | 358 | 363 | 368 | 373 | 378 | 383 | 388 | 393 | 394 | 395 | -------------------------------------------------------------------------------- /dist/fonts/main-fonts.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DigitalCloud/nova-page-builder-field/19e2460c3de232592511d55176ddee71a5ad5947/dist/fonts/main-fonts.ttf -------------------------------------------------------------------------------- /dist/fonts/main-fonts.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DigitalCloud/nova-page-builder-field/19e2460c3de232592511d55176ddee71a5ad5947/dist/fonts/main-fonts.woff -------------------------------------------------------------------------------- /dist/mix-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "/js/field.js": "/js/field.js", 3 | "/css/field.css": "/css/field.css" 4 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "dev": "npm run development", 5 | "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 6 | "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 7 | "watch-poll": "npm run watch -- --watch-poll", 8 | "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js", 9 | "prod": "npm run production", 10 | "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js" 11 | }, 12 | "devDependencies": { 13 | "cross-env": "^5.0.0", 14 | "laravel-mix": "^1.0", 15 | "laravel-nova": "^1.0" 16 | }, 17 | "dependencies": { 18 | "grapesjs": "0.x", 19 | "grapesjs-aviary": "^0.1.2", 20 | "grapesjs-blocks-basic": "^0.1.7", 21 | "grapesjs-component-countdown": "^0.1.2", 22 | "grapesjs-navbar": "^0.1.5", 23 | "grapesjs-plugin-export": "^0.1.5", 24 | "grapesjs-plugin-filestack": "^0.1.1", 25 | "grapesjs-plugin-forms": "^0.3.5", 26 | "vue": "^2.5.0" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /resources/css/demos.css: -------------------------------------------------------------------------------- 1 | body, 2 | html { 3 | height: 100%; 4 | margin: 0; 5 | overflow: hidden; 6 | } 7 | 8 | #toast-container { 9 | font-size: 13px; 10 | font-weight: lighter; 11 | } 12 | 13 | #toast-container > div { 14 | opacity: 0.95; 15 | } 16 | 17 | #toast-container > div, 18 | #toast-container > div:hover { 19 | box-shadow: 0 0 12px rgba(0, 0, 0, 0.1); 20 | font-family: Helvetica, sans-serif; 21 | } 22 | 23 | /* LOGO VERSION */ 24 | 25 | .gjs-pn-commands .gjs-pn-buttons, 26 | #gjs-pn-commands .gjs-pn-buttons { 27 | display: none; 28 | } 29 | 30 | .gjs-logo { 31 | height: 25px; 32 | } 33 | 34 | .gjs-logo-cont { 35 | position: relative; 36 | display: inline-block; 37 | top: 3px; 38 | } 39 | 40 | .gjs-logo-version { 41 | position: absolute; 42 | font-size: 10px; 43 | padding: 1px 7px; 44 | border-radius: 15px; 45 | bottom: 2px; 46 | right: -43px; 47 | } 48 | 49 | /* INFO PANEL */ 50 | 51 | .gjs-mdl-dialog-sm { 52 | width: 300px; 53 | } 54 | 55 | #info-panel { 56 | line-height: 17px; 57 | } 58 | 59 | .info-panel-logo { 60 | display: block; 61 | height: 90px; 62 | margin: 0 auto; 63 | width: 90px; 64 | } 65 | 66 | .info-panel-logo path { 67 | stroke: #eee !important; 68 | stroke-width: 8 !important; 69 | } 70 | 71 | .info-panel-label { 72 | margin-bottom: 10px; 73 | font-size: 13px; 74 | } 75 | 76 | .info-panel-link { 77 | text-decoration: none; 78 | } 79 | 80 | /* ADS */ 81 | 82 | .gjs-pn-panel#gjs-pn-views-container, 83 | .gjs-pn-panel.gjs-pn-views-container { 84 | height: calc(100% - 150px); 85 | } 86 | 87 | .ad-cont { 88 | position: absolute; 89 | right: 0; 90 | bottom: 0; 91 | z-index: 2; 92 | width: 15%; 93 | height: 150px; 94 | } 95 | 96 | #carbonads { 97 | padding: 20px 10px; 98 | } 99 | 100 | .carbon-img { 101 | float: right; 102 | margin-left: 10px; 103 | } 104 | 105 | .carbon-img img { 106 | border-radius: 3px; 107 | max-width: 100px !important; 108 | max-height: 77px; 109 | } 110 | 111 | .carbon-text { 112 | color: rgba(255, 255, 255, 0.75); 113 | font: caption; 114 | text-decoration: none; 115 | font-weight: lighter; 116 | } 117 | 118 | .carbon-poweredby { 119 | font: caption; 120 | color: rgba(255, 255, 255, 0.55); 121 | text-decoration: none; 122 | float: right; 123 | } 124 | -------------------------------------------------------------------------------- /resources/css/grapes-code-editor.min.css: -------------------------------------------------------------------------------- 1 | .code-panel{text-align:left;font-size:1rem;height:100%}.code-panel section{height:50%}.code-panel section .codepanel-separator{display:flex;justify-content:space-between;padding-left:0.6rem;padding-right:0.6rem}.code-panel section .codepanel-label{line-height:20px;font-size:13px;color:#aaa;user-select:none;text-transform:uppercase}.gutter{cursor:ns-resize;position:relative;background-color:rgba(0,0,0,0.2)}.gutter:after{content:'';display:block;height:8px;width:100%;position:absolute;top:-3px;z-index:150}.code-panel .CodeMirror{height:calc(100% - 20px)}.gjs-pn-views{border-left:1px solid rgba(0,0,0,0.2);border-bottom:0}.gjs-pn-views-container{box-shadow:initial;border-top:2px solid rgba(0,0,0,0.2);top:40px;padding-top:0;height:calc(100vh - 40px)}.gjs-pn-views-container,.gjs-cv-canvas{transition:width 0.3s ease-in-out} 2 | -------------------------------------------------------------------------------- /resources/css/grapesjs-plugin-filestack.css: -------------------------------------------------------------------------------- 1 | .gjs-am-assets-cont .gjs-am-asset-image { 2 | border-bottom: none; 3 | float: left; 4 | width: 20%; 5 | height: 150px; 6 | box-sizing: border-box; 7 | border-radius: 3px; 8 | overflow: hidden; } 9 | 10 | .gjs-am-assets-cont #gjs-am-meta, 11 | .gjs-am-assets-cont #gjs-am-preview-cont { 12 | width: 100%; } 13 | 14 | .gjs-am-assets-cont #gjs-am-preview-cont { 15 | height: 100px; } 16 | 17 | .gjs-am-assets-cont #gjs-am-close { 18 | right: 10px; 19 | top: 10px; 20 | z-index: 1; 21 | line-height: 0; } 22 | 23 | .gjs-btn-filestack { 24 | margin-bottom: 10px; } 25 | 26 | .gjs-am-assets-cont { 27 | height: 400px; } 28 | 29 | .gjs-am-assets { 30 | height: 345px; 31 | background-color: rgba(0, 0, 0, 0.1); 32 | padding: 5px; 33 | margin: 0 -10px; } 34 | -------------------------------------------------------------------------------- /resources/css/grapesjs-preset-webpage.min.css: -------------------------------------------------------------------------------- 1 | .gjs-one-bg{background-color:#463a3c}.gjs-one-color{color:#463a3c}.gjs-one-color-h:hover{color:#463a3c}.gjs-two-bg{background-color:#b9a5a6}.gjs-two-color{color:#b9a5a6}.gjs-two-color-h:hover{color:#b9a5a6}.gjs-three-bg{background-color:#804f7b}.gjs-three-color{color:#804f7b}.gjs-three-color-h:hover{color:#804f7b}.gjs-four-bg{background-color:#d97aa6}.gjs-four-color{color:#d97aa6}.gjs-four-color-h:hover{color:#d97aa6} 2 | -------------------------------------------------------------------------------- /resources/css/toastr.min.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Note that this is toastr v2.1.3, the "latest" version in url has no more maintenance, 3 | * please go to https://cdnjs.com/libraries/toastr.js and pick a certain version you want to use, 4 | * make sure you copy the url from the website since the url may change between versions. 5 | * */ 6 | .toast-title{font-weight:700}.toast-message{-ms-word-wrap:break-word;word-wrap:break-word}.toast-message a,.toast-message label{color:#FFF}.toast-message a:hover{color:#CCC;text-decoration:none}.toast-close-button{position:relative;right:-.3em;top:-.3em;float:right;font-size:20px;font-weight:700;color:#FFF;-webkit-text-shadow:0 1px 0 #fff;text-shadow:0 1px 0 #fff;opacity:.8;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80);filter:alpha(opacity=80);line-height:1}.toast-close-button:focus,.toast-close-button:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.4;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=40);filter:alpha(opacity=40)}.rtl .toast-close-button{left:-.3em;float:left;right:.3em}button.toast-close-button{padding:0;cursor:pointer;background:0 0;border:0;-webkit-appearance:none}.toast-top-center{top:0;right:0;width:100%}.toast-bottom-center{bottom:0;right:0;width:100%}.toast-top-full-width{top:0;right:0;width:100%}.toast-bottom-full-width{bottom:0;right:0;width:100%}.toast-top-left{top:12px;left:12px}.toast-top-right{top:12px;right:12px}.toast-bottom-right{right:12px;bottom:12px}.toast-bottom-left{bottom:12px;left:12px}#toast-container{position:fixed;z-index:999999;pointer-events:none}#toast-container *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}#toast-container>div{position:relative;pointer-events:auto;overflow:hidden;margin:0 0 6px;padding:15px 15px 15px 50px;width:300px;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;background-position:15px center;background-repeat:no-repeat;-moz-box-shadow:0 0 12px #999;-webkit-box-shadow:0 0 12px #999;box-shadow:0 0 12px #999;color:#FFF;opacity:.8;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80);filter:alpha(opacity=80)}#toast-container>div.rtl{direction:rtl;padding:15px 50px 15px 15px;background-position:right 15px center}#toast-container>div:hover{-moz-box-shadow:0 0 12px #000;-webkit-box-shadow:0 0 12px #000;box-shadow:0 0 12px #000;opacity:1;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=100);filter:alpha(opacity=100);cursor:pointer}#toast-container>.toast-info{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=)!important}#toast-container>.toast-error{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=)!important}#toast-container>.toast-success{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==)!important}#toast-container>.toast-warning{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=)!important}#toast-container.toast-bottom-center>div,#toast-container.toast-top-center>div{width:300px;margin-left:auto;margin-right:auto}#toast-container.toast-bottom-full-width>div,#toast-container.toast-top-full-width>div{width:96%;margin-left:auto;margin-right:auto}.toast{background-color:#030303}.toast-success{background-color:#51A351}.toast-error{background-color:#BD362F}.toast-info{background-color:#2F96B4}.toast-warning{background-color:#F89406}.toast-progress{position:absolute;left:0;bottom:0;height:4px;background-color:#000;opacity:.4;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=40);filter:alpha(opacity=40)}@media all and (max-width:240px){#toast-container>div{padding:8px 8px 8px 50px;width:11em}#toast-container>div.rtl{padding:8px 50px 8px 8px}#toast-container .toast-close-button{right:-.2em;top:-.2em}#toast-container .rtl .toast-close-button{left:-.2em;right:.2em}}@media all and (min-width:241px) and (max-width:480px){#toast-container>div{padding:8px 8px 8px 50px;width:18em}#toast-container>div.rtl{padding:8px 50px 8px 8px}#toast-container .toast-close-button{right:-.2em;top:-.2em}#toast-container .rtl .toast-close-button{left:-.2em;right:.2em}}@media all and (min-width:481px) and (max-width:768px){#toast-container>div{padding:15px 15px 15px 50px;width:25em}#toast-container>div.rtl{padding:15px 50px 15px 15px}} 7 | -------------------------------------------------------------------------------- /resources/css/tooltip.css: -------------------------------------------------------------------------------- 1 | [data-tooltip] { 2 | position: relative; 3 | } 4 | 5 | [data-tooltip]::after { 6 | font-family: Helvetica, sans-serif; 7 | background: rgba(51, 51, 51, 0.9); 8 | background: rgba(55, 61, 73, 0.9); 9 | border-radius: 3px; 10 | bottom: 100%; 11 | color: #fff; 12 | content: attr(data-tooltip); 13 | display: block; 14 | font-size: 12px; 15 | left: 50%; 16 | line-height: normal; 17 | max-width: 32rem; 18 | opacity: 0; 19 | overflow: hidden; 20 | padding: 0.6rem 1rem; 21 | pointer-events: none; 22 | position: absolute; 23 | text-overflow: ellipsis; 24 | -webkit-transform: translate(-50%, 0); 25 | -ms-transform: translate(-50%, 0); 26 | transform: translate(-50%, 0); 27 | transition: all 0.216s ease; 28 | z-index: 99; 29 | } 30 | 31 | [data-tooltip]:focus::after, 32 | [data-tooltip]:hover::after { 33 | opacity: 1; 34 | -webkit-transform: translate(-50%, -0.5rem); 35 | -ms-transform: translate(-50%, -0.5rem); 36 | transform: translate(-50%, -0.5rem); 37 | } 38 | 39 | [data-tooltip][disabled], 40 | [data-tooltip].disabled { 41 | pointer-events: auto; 42 | } 43 | 44 | [data-tooltip-pos=right]::after { 45 | bottom: 50%; 46 | left: 100%; 47 | -webkit-transform: translate(0, 50%); 48 | -ms-transform: translate(0, 50%); 49 | transform: translate(0, 50%); 50 | } 51 | 52 | [data-tooltip-pos=right]:focus::after, 53 | [data-tooltip-pos=right]:hover::after { 54 | -webkit-transform: translate(0.5rem, 50%); 55 | -ms-transform: translate(0.5rem, 50%); 56 | transform: translate(0.5rem, 50%); 57 | } 58 | 59 | [data-tooltip-pos=bottom]::after { 60 | bottom: auto; 61 | top: 100%; 62 | -webkit-transform: translate(-50%, 0); 63 | -ms-transform: translate(-50%, 0); 64 | transform: translate(-50%, 0); 65 | } 66 | 67 | [data-tooltip-pos=bottom]:focus::after, 68 | [data-tooltip-pos=bottom]:hover::after { 69 | -webkit-transform: translate(-50%, 0.5rem); 70 | -ms-transform: translate(-50%, 0.5rem); 71 | transform: translate(-50%, 0.5rem); 72 | } 73 | 74 | [data-tooltip-pos=left]::after { 75 | bottom: 50%; 76 | left: auto; 77 | right: 100%; 78 | -webkit-transform: translate(0, 50%); 79 | -ms-transform: translate(0, 50%); 80 | transform: translate(0, 50%); 81 | } 82 | 83 | [data-tooltip-pos=left]:focus::after, 84 | [data-tooltip-pos=left]:hover::after { 85 | -webkit-transform: translate(-0.5rem, 50%); 86 | -ms-transform: translate(-0.5rem, 50%); 87 | transform: translate(-0.5rem, 50%); 88 | } 89 | -------------------------------------------------------------------------------- /resources/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DigitalCloud/nova-page-builder-field/19e2460c3de232592511d55176ddee71a5ad5947/resources/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /resources/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DigitalCloud/nova-page-builder-field/19e2460c3de232592511d55176ddee71a5ad5947/resources/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /resources/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DigitalCloud/nova-page-builder-field/19e2460c3de232592511d55176ddee71a5ad5947/resources/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /resources/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DigitalCloud/nova-page-builder-field/19e2460c3de232592511d55176ddee71a5ad5947/resources/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /resources/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DigitalCloud/nova-page-builder-field/19e2460c3de232592511d55176ddee71a5ad5947/resources/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /resources/fonts/main-fonts.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DigitalCloud/nova-page-builder-field/19e2460c3de232592511d55176ddee71a5ad5947/resources/fonts/main-fonts.eot -------------------------------------------------------------------------------- /resources/fonts/main-fonts.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 29 | 34 | 35 | 42 | 51 | 55 | 58 | 63 | 68 | 73 | 78 | 83 | 88 | 93 | 98 | 103 | 108 | 113 | 118 | 123 | 128 | 133 | 138 | 143 | 148 | 153 | 154 | 155 | 186 | 196 | 197 | 199 | 200 | 202 | image/svg+xml 203 | 205 | 206 | 207 | 208 | 209 | 214 | 219 | 224 | 229 | 234 | 240 | 245 | 248 | 253 | 254 | 269 | 285 | 290 | Borders: 30pxCanvas: 1000x1000px 308 | 312 | 315 | 317 | 321 | 325 | 329 | 333 | 337 | 341 | 345 | 349 | 350 | 351 | 352 | 353 | 358 | 363 | 368 | 373 | 378 | 383 | 388 | 393 | 394 | 395 | -------------------------------------------------------------------------------- /resources/fonts/main-fonts.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DigitalCloud/nova-page-builder-field/19e2460c3de232592511d55176ddee71a5ad5947/resources/fonts/main-fonts.ttf -------------------------------------------------------------------------------- /resources/fonts/main-fonts.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DigitalCloud/nova-page-builder-field/19e2460c3de232592511d55176ddee71a5ad5947/resources/fonts/main-fonts.woff -------------------------------------------------------------------------------- /resources/js/components/DetailField.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 13 | -------------------------------------------------------------------------------- /resources/js/components/FormField.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 95 | -------------------------------------------------------------------------------- /resources/js/field.js: -------------------------------------------------------------------------------- 1 | Nova.booting((Vue, router) => { 2 | Vue.component('detail-page-builder-field', require('./components/DetailField')); 3 | Vue.component('form-page-builder-field', require('./components/FormField')); 4 | }) 5 | -------------------------------------------------------------------------------- /resources/js/plugins/custom.js: -------------------------------------------------------------------------------- 1 | import grapesjs from 'grapesjs'; 2 | 3 | export default grapesjs.plugins.add('custom', function (editor, opts) { 4 | 5 | var opt = opts || {}; 6 | var config = editor.getConfig(); 7 | var pfx = editor.getConfig().stylePrefix; 8 | var modal = editor.Modal; 9 | var $ = window.$ || grapesjs.$; 10 | 11 | config.showDevices = 0; 12 | 13 | var updateTooltip = function (coll, pos) { 14 | coll.each(function (item) { 15 | var attrs = item.get('attributes'); 16 | attrs['data-tooltip-pos'] = pos || 'bottom'; 17 | item.set('attributes', attrs); 18 | }); 19 | } 20 | 21 | /****************** IMPORTER *************************/ 22 | 23 | var codeViewer = editor.CodeManager.getViewer('CodeMirror').clone(); 24 | var container = document.createElement('div'); 25 | var btnImp = document.createElement('button'); 26 | 27 | // Init import button 28 | btnImp.innerHTML = 'Import'; 29 | btnImp.className = pfx + 'btn-prim ' + pfx + 'btn-import'; 30 | btnImp.onclick = function () { 31 | var code = codeViewer.editor.getValue(); 32 | editor.DomComponents.getWrapper().set('content', ''); 33 | editor.setComponents(code.trim()); 34 | modal.close(); 35 | }; 36 | 37 | // Init code viewer 38 | codeViewer.set({ 39 | codeName: 'htmlmixed', 40 | theme: opt.codeViewerTheme || 'hopscotch', 41 | readOnly: 0 42 | }); 43 | 44 | 45 | /****************** COMMANDS *************************/ 46 | 47 | var cmdm = editor.Commands; 48 | cmdm.add('undo', { 49 | run: function (editor, sender) { 50 | sender.set('active', 0); 51 | editor.UndoManager.undo(1); 52 | } 53 | }); 54 | cmdm.add('redo', { 55 | run: function (editor, sender) { 56 | sender.set('active', 0); 57 | editor.UndoManager.redo(1); 58 | } 59 | }); 60 | cmdm.add('set-device-desktop', { 61 | run: function (editor) { 62 | editor.setDevice('Desktop'); 63 | } 64 | }); 65 | cmdm.add('set-device-tablet', { 66 | run: function (editor) { 67 | editor.setDevice('Tablet'); 68 | } 69 | }); 70 | cmdm.add('set-device-mobile', { 71 | run: function (editor) { 72 | editor.setDevice('Mobile portrait'); 73 | } 74 | }); 75 | cmdm.add('clean-all', { 76 | run: function (editor, sender) { 77 | sender && sender.set('active', false); 78 | if (confirm('Are you sure to clean the canvas?')) { 79 | var comps = editor.DomComponents.clear(); 80 | setTimeout(function () { 81 | localStorage.clear() 82 | }, 0) 83 | } 84 | } 85 | }); 86 | 87 | cmdm.add('html-import', { 88 | run: function (editor, sender) { 89 | sender && sender.set('active', 0); 90 | 91 | var modalContent = modal.getContentEl(); 92 | var viewer = codeViewer.editor; 93 | modal.setTitle('Import Template'); 94 | 95 | // Init code viewer if not yet instantiated 96 | if (!viewer) { 97 | var txtarea = document.createElement('textarea'); 98 | var labelEl = document.createElement('div'); 99 | labelEl.className = pfx + 'import-label'; 100 | labelEl.innerHTML = 'Paste here your HTML/CSS and click Import'; 101 | container.appendChild(labelEl); 102 | container.appendChild(txtarea); 103 | container.appendChild(btnImp); 104 | codeViewer.init(txtarea); 105 | viewer = codeViewer.editor; 106 | } 107 | 108 | modal.setContent(''); 109 | modal.setContent(container); 110 | codeViewer.setContent( 111 | '
Hello world!
' + 112 | '' 113 | ); 114 | modal.open(); 115 | viewer.refresh(); 116 | } 117 | }); 118 | 119 | /****************** BLOCKS *************************/ 120 | 121 | var bm = editor.BlockManager; 122 | 123 | bm.add('quote', { 124 | label: 'Quote', 125 | category: 'Basic', 126 | content: '
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore ipsum dolor sit
', 127 | attributes: {class: 'fa fa-quote-right'} 128 | }); 129 | 130 | bm.add('section-hero', { 131 | label: 'Hero section', 132 | category: 'Sections', 133 | content: `` + '
' + 217 | '
' + 218 | '
' + 221 | '
Build your templates without coding
' + 222 | '
Try it now
', 223 | attributes: {class: 'gjs-fonts gjs-f-hero'} 224 | }); 225 | 226 | bm.add('section-badges', { 227 | label: 'Badges', 228 | category: 'Sections', 229 | content: `
310 |
311 |

The team

312 |
313 |
314 |
315 |
316 | 317 |
318 |
Adam Smith 319 |
320 |
CEO 321 |
322 |
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore ipsum dolor sit 323 |
324 |
325 |
326 | f 327 | t 328 | ln 329 |
330 |
331 |
332 |
333 |
334 | 335 |
336 |
John Black 337 |
338 |
Software Engineer 339 |
340 |
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore ipsum dolor sit 341 |
342 |
343 |
344 | f 345 | t 346 | ln 347 |
348 |
349 |
350 |
351 |
352 | 353 |
354 |
Jessica White 355 |
356 |
Web Designer 357 |
358 |
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore ipsum dolor sit 359 |
360 |
361 |
362 | f 363 | t 364 | ln 365 |
366 |
367 |
368 |
369 |
370 | `, 371 | attributes: {class: 'gjs-fonts gjs-f-h1p'} 372 | }); 373 | // 374 | // bm.add('section-typography', { 375 | // label: 'Text section', 376 | // category: 'Sections', 377 | // content: `
378 | //

Insert title here

379 | //

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua

380 | //
`, 381 | // attributes: {class: 'gjs-fonts gjs-f-h1p'} 382 | // }); 383 | // 384 | bm.add('section-cards', { 385 | label: 'Cards', 386 | category: 'Sections', 387 | content: `
449 |
450 |
451 |
452 |
453 |
Title one 454 |
455 |
Subtitle one 456 |
457 |
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore 458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
Title two 466 |
467 |
Subtitle one 468 |
469 |
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore 470 |
471 |
472 |
473 |
`, 474 | attributes: {class: 'gjs-fonts gjs-f-3ba'} 475 | }); 476 | 477 | bm.add('section-card', { 478 | label: 'Card', 479 | category: 'Sections', 480 | content: ` 542 |
543 |
544 |
545 |
Title one 546 |
547 |
Subtitle one 548 |
549 |
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore 550 |
551 |
552 |
553 | 554 | `, 555 | attributes: {class: 'gjs-fonts gjs-f-3ba'} 556 | }); 557 | 558 | 559 | 560 | 561 | /****************** BUTTONS *************************/ 562 | 563 | var pnm = editor.Panels; 564 | pnm.addButton('options', [{ 565 | id: 'undo', 566 | className: 'fa fa-undo icon-undo', 567 | command: 'undo', 568 | attributes: {title: 'Undo (CTRL/CMD + Z)'} 569 | }, { 570 | id: 'redo', 571 | className: 'fa fa-repeat icon-redo', 572 | command: 'redo', 573 | attributes: {title: 'Redo (CTRL/CMD + SHIFT + Z)'} 574 | }, { 575 | id: 'import', 576 | className: 'fa fa-download', 577 | command: 'html-import', 578 | attributes: {title: 'Import'} 579 | }, { 580 | id: 'clean-all', 581 | className: 'fa fa-trash icon-blank', 582 | command: 'clean-all', 583 | attributes: {title: 'Empty canvas'} 584 | }]); 585 | 586 | // Add devices buttons 587 | var panelDevices = pnm.addPanel({id: 'devices-c'}); 588 | var deviceBtns = panelDevices.get('buttons'); 589 | deviceBtns.add([{ 590 | id: 'deviceDesktop', 591 | command: 'set-device-desktop', 592 | className: 'fa fa-desktop', 593 | attributes: {'title': 'Desktop'}, 594 | active: 1, 595 | }, { 596 | id: 'deviceTablet', 597 | command: 'set-device-tablet', 598 | className: 'fa fa-tablet', 599 | attributes: {'title': 'Tablet'}, 600 | }, { 601 | id: 'deviceMobile', 602 | command: 'set-device-mobile', 603 | className: 'fa fa-mobile', 604 | attributes: {'title': 'Mobile'}, 605 | }]); 606 | updateTooltip(deviceBtns); 607 | updateTooltip(pnm.getPanel('options').get('buttons')); 608 | 609 | 610 | /****************** EVENTS *************************/ 611 | 612 | // On component change show the Style Manager 613 | editor.on('change:selectedComponent', function () { 614 | var openLayersBtn = editor.Panels.getButton('views', 'open-layers'); 615 | 616 | // Don't switch when the Layer Manager is on or 617 | // there is no selected component 618 | if ((!openLayersBtn || !openLayersBtn.get('active')) && 619 | editor.editor.get('selectedComponent')) { 620 | var openSmBtn = editor.Panels.getButton('views', 'open-sm'); 621 | openSmBtn && openSmBtn.set('active', 1); 622 | } 623 | }); 624 | 625 | }); 626 | -------------------------------------------------------------------------------- /resources/sass/field.scss: -------------------------------------------------------------------------------- 1 | // Nova Tool CSS 2 | @import "../css/grapes.min.css"; 3 | @import "../css/tooltip.css"; 4 | 5 | -------------------------------------------------------------------------------- /src/FieldServiceProvider.php: -------------------------------------------------------------------------------- 1 | publishes([ 19 | __DIR__.'/../resources/fonts' => public_path('/fonts'), 20 | ], 'public'); 21 | 22 | Nova::serving(function (ServingNova $event) { 23 | Nova::script('page-builder-field', __DIR__.'/../dist/js/field.js'); 24 | Nova::style('page-builder-field', __DIR__.'/../dist/css/field.css'); 25 | }); 26 | } 27 | 28 | /** 29 | * Register any application services. 30 | * 31 | * @return void 32 | */ 33 | public function register() 34 | { 35 | // 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/PageBuilderField.php: -------------------------------------------------------------------------------- 1 | hideFromIndex(); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /webpack.mix.js: -------------------------------------------------------------------------------- 1 | let mix = require('laravel-mix') 2 | 3 | mix.setPublicPath('dist') 4 | .js('resources/js/field.js', 'js') 5 | .sass('resources/sass/field.scss', 'css') 6 | --------------------------------------------------------------------------------