├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitattributes ├── .gitignore ├── .prettierrc.yaml ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── admin └── src │ ├── components │ ├── GrapesEditor │ │ ├── assets │ │ │ ├── fonts │ │ │ │ ├── main-fonts.eot │ │ │ │ ├── main-fonts.svg │ │ │ │ ├── main-fonts.ttf │ │ │ │ └── main-fonts.woff │ │ │ ├── img │ │ │ │ └── demo.png │ │ │ ├── js │ │ │ │ └── fa-shim.js │ │ │ └── scss │ │ │ │ ├── _variables.scss │ │ │ │ ├── grapes_main.scss │ │ │ │ └── main.scss │ │ ├── config │ │ │ ├── device-manager.config.js │ │ │ ├── editor.config.js │ │ │ ├── storage-manager.config.js │ │ │ └── style-manager.config.js │ │ ├── grapes-plugins │ │ │ └── strapi │ │ │ │ ├── blocks.js │ │ │ │ ├── components.js │ │ │ │ ├── consts.js │ │ │ │ ├── image.block.js │ │ │ │ ├── index.js │ │ │ │ └── panels.js │ │ └── index.js │ └── Wysiwyg │ │ └── index.js │ ├── containers │ ├── App │ │ └── index.js │ ├── HomePage │ │ └── index.js │ ├── Initializer │ │ └── index.js │ └── Settings │ │ └── index.js │ ├── index.js │ ├── lifecycles.js │ ├── pluginId.js │ ├── translations │ ├── ar.json │ ├── cs.json │ ├── de.json │ ├── en.json │ ├── es.json │ ├── fr.json │ ├── index.js │ ├── it.json │ ├── ko.json │ ├── nl.json │ ├── pl.json │ ├── pt-BR.json │ ├── pt.json │ ├── ru.json │ ├── sk.json │ ├── tr.json │ ├── vi.json │ ├── zh-Hans.json │ └── zh.json │ └── utils │ └── getTrad.js ├── config └── routes.json ├── controllers └── strapi-plugin-webpage-builder.js ├── main.scss ├── package-lock.json ├── package.json └── services └── strapi-plugin-webpage-builder.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | indent_style = space 7 | indent_size = 2 8 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | .cache 2 | build 3 | **/node_modules/** 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parserOptions": { 3 | "ecmaFeatures": { 4 | "jsx": true, 5 | "modules": true, 6 | "sourceType": "module", 7 | "parser": "babel-eslint" 8 | } 9 | }, 10 | "settings": { 11 | "import/resolver": { 12 | "node": { 13 | "extensions": [ 14 | ".js", 15 | ".jsx" 16 | ] 17 | } 18 | } 19 | }, 20 | "extends": [ 21 | "standard", 22 | "standard-react", 23 | "plugin:import/errors", 24 | "plugin:react/recommended", 25 | "prettier", 26 | "prettier/react", 27 | "prettier/standard", 28 | "plugin:prettier/recommended" 29 | ], 30 | "rules": { 31 | "quotes": [ 32 | "error", 33 | "single" 34 | ], 35 | "import/imports-first": [ 36 | "error", 37 | "absolute-first" 38 | ], 39 | "import/newline-after-import": "error", 40 | "no-console": 0, 41 | "no-shadow": [ 42 | "error", 43 | { 44 | "hoist": "functions" 45 | } 46 | ], 47 | "padding-line-between-statements": [ 48 | "error", 49 | { 50 | "blankLine": "always", 51 | "prev": "*", 52 | "next": "return" 53 | }, 54 | { 55 | "blankLine": "always", 56 | "prev": "block-like", 57 | "next": "*" 58 | } 59 | ], 60 | "eol-last": [ 61 | "error", 62 | "always" 63 | ], 64 | "no-alert": 2, 65 | "no-else-return": 2, 66 | "no-eval": 2, 67 | "no-lone-blocks": 2, 68 | "no-loop-func": 2, 69 | "no-magic-numbers": [ 70 | 0, 71 | { 72 | "ignoreArrayIndexes": true, 73 | "enforceConst": true 74 | } 75 | ], 76 | "radix": 2, 77 | "no-unneeded-ternary": 2, 78 | "no-var": 2, 79 | "prefer-const": 2, 80 | "react/no-unescaped-entities": 0, 81 | "react/jsx-pascal-case": 0, 82 | "react/prop-types": 0, 83 | "no-new": 0, 84 | "click-events-have-key-events": 0, 85 | "indent": [ 86 | "error", 87 | 2 88 | ] 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # From https://github.com/Danimoth/gitattributes/blob/master/Web.gitattributes 2 | 3 | # Handle line endings automatically for files detected as text 4 | # and leave all files detected as binary untouched. 5 | * text=auto 6 | 7 | # 8 | # The above will handle all files NOT found below 9 | # 10 | 11 | # 12 | ## These files are text and should be normalized (Convert crlf => lf) 13 | # 14 | 15 | # source code 16 | *.php text 17 | *.css text 18 | *.sass text 19 | *.scss text 20 | *.less text 21 | *.styl text 22 | *.js text eol=lf 23 | *.coffee text 24 | *.json text 25 | *.htm text 26 | *.html text 27 | *.xml text 28 | *.svg text 29 | *.txt text 30 | *.ini text 31 | *.inc text 32 | *.pl text 33 | *.rb text 34 | *.py text 35 | *.scm text 36 | *.sql text 37 | *.sh text 38 | *.bat text 39 | 40 | # templates 41 | *.ejs text 42 | *.hbt text 43 | *.jade text 44 | *.haml text 45 | *.hbs text 46 | *.dot text 47 | *.tmpl text 48 | *.phtml text 49 | 50 | # git config 51 | .gitattributes text 52 | .gitignore text 53 | .gitconfig text 54 | 55 | # code analysis config 56 | .jshintrc text 57 | .jscsrc text 58 | .jshintignore text 59 | .csslintrc text 60 | 61 | # misc config 62 | *.yaml text 63 | *.yml text 64 | .editorconfig text 65 | 66 | # build config 67 | *.npmignore text 68 | *.bowerrc text 69 | 70 | # Heroku 71 | Procfile text 72 | .slugignore text 73 | 74 | # Documentation 75 | *.md text 76 | LICENSE text 77 | AUTHORS text 78 | 79 | 80 | # 81 | ## These files are binary and should be left untouched 82 | # 83 | 84 | # (binary is a macro for -text -diff) 85 | *.png binary 86 | *.jpg binary 87 | *.jpeg binary 88 | *.gif binary 89 | *.ico binary 90 | *.mov binary 91 | *.mp4 binary 92 | *.mp3 binary 93 | *.flv binary 94 | *.fla binary 95 | *.swf binary 96 | *.gz binary 97 | *.zip binary 98 | *.7z binary 99 | *.ttf binary 100 | *.eot binary 101 | *.woff binary 102 | *.pyc binary 103 | *.pdf binary 104 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Don't check auto-generated stuff into git 2 | coverage 3 | node_modules 4 | stats.json 5 | 6 | # Cruft 7 | .DS_Store 8 | npm-debug.log 9 | .idea 10 | -------------------------------------------------------------------------------- /.prettierrc.yaml: -------------------------------------------------------------------------------- 1 | printWidth: 120 2 | tabWidth: 2 3 | useTabs: false 4 | singleQuote: true 5 | trailingComma: es5 6 | arrowParens: always 7 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.tabSize": 2, 3 | "editor.defaultFormatter": "esbenp.prettier-vscode", 4 | "editor.formatOnSave": true 5 | } 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 uwizy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # strapi-plugin-webpage-builder 2 | Add GrapesJS builder to your own strapi application 3 | 4 | ![Webpage builder demo](/admin/src/components/GrapesEditor/assets/img/demo.png) 5 | 6 | # Setup 7 | Install package 8 | ```sh 9 | npm i --save strapi-plugin-webpage-builder 10 | # or 11 | yarn add strapi-plugin-webpage-builder 12 | ``` 13 | 14 | Create or edit `your-project/admin/admin.config.js` and add sass loader (which is required by GrapesJS) 15 | ```javascript 16 | module.exports = { 17 | webpack: (config, webpack) => { 18 | // Note: we provide webpack above so you should not `require` it 19 | // Perform customizations to webpack config 20 | // Important: return the modified config 21 | 22 | // Allow scss modules 23 | config.resolve = { ...config.resolve, extensions: [...config.resolve.extensions, '.scss'] }; 24 | 25 | // Configure a SASS loader 26 | config.module.rules.push({ 27 | test: /\.s[ac]ss$/i, 28 | use: [ 29 | 'style-loader', 30 | 'css-loader', 31 | 'sass-loader', 32 | { 33 | loader: 'sass-loader', 34 | options: { 35 | implementation: require('sass'), 36 | }, 37 | }, 38 | ], 39 | }); 40 | 41 | return config; 42 | }, 43 | }; 44 | ``` 45 | 46 | Edit your model(e.g. the model that'll handle web builder field) controllers (`your-project/api/your-model/controllers/your-model.js`). 47 | > At the time of this release, strapi does not allow to add custom private fields to model so all the data required to init editor will be stored in your model. The following step prevent useless data to be returned on get requests: 48 | ```javascript 49 | 'use strict'; 50 | const { sanitizeEntity } = require('strapi-utils'); 51 | 52 | const cleanupEntity = (entity) => { 53 | const { content } = entity; 54 | 55 | return { ...entity, content: { html: content.html, css: content.css } }; 56 | }; 57 | 58 | module.exports = { 59 | async find(ctx) { 60 | let entities; 61 | if (ctx.query._q) { 62 | entities = await strapi.services.yourModel.search(ctx.query); /* eslint-disable-line no-undef */ 63 | } else { 64 | entities = await strapi.services.yourModel.find(ctx.query); /* eslint-disable-line no-undef */ 65 | } 66 | 67 | return entities.map((entity) => { 68 | return sanitizeEntity(cleanupEntity(entity), { model: strapi.models.yourModel } /* eslint-disable-line no-undef */); 69 | }); 70 | }, 71 | async findOne(ctx) { 72 | const { id } = ctx.params; 73 | 74 | const entity = await strapi.services.yourModel.findOne({ id }); /* eslint-disable-line no-undef */ 75 | 76 | return sanitizeEntity(cleanupEntity(entity), { model: strapi.models.yourModel } /* eslint-disable-line no-undef */); 77 | }, 78 | }; 79 | ``` 80 | > NB: this code assumes that you named a field `content` with type `json` in model `yourModel` 81 | -------------------------------------------------------------------------------- /admin/src/components/GrapesEditor/assets/fonts/main-fonts.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uwizy/strapi-plugin-webpage-builder/e0bc576de7aa01e39791282565aa339b970cfae8/admin/src/components/GrapesEditor/assets/fonts/main-fonts.eot -------------------------------------------------------------------------------- /admin/src/components/GrapesEditor/assets/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 | -------------------------------------------------------------------------------- /admin/src/components/GrapesEditor/assets/fonts/main-fonts.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uwizy/strapi-plugin-webpage-builder/e0bc576de7aa01e39791282565aa339b970cfae8/admin/src/components/GrapesEditor/assets/fonts/main-fonts.ttf -------------------------------------------------------------------------------- /admin/src/components/GrapesEditor/assets/fonts/main-fonts.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uwizy/strapi-plugin-webpage-builder/e0bc576de7aa01e39791282565aa339b970cfae8/admin/src/components/GrapesEditor/assets/fonts/main-fonts.woff -------------------------------------------------------------------------------- /admin/src/components/GrapesEditor/assets/img/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uwizy/strapi-plugin-webpage-builder/e0bc576de7aa01e39791282565aa339b970cfae8/admin/src/components/GrapesEditor/assets/img/demo.png -------------------------------------------------------------------------------- /admin/src/components/GrapesEditor/assets/js/fa-shim.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | /*! 3 | * Font Awesome Free 5.13.0 by @fontawesome - https://fontawesome.com 4 | * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) 5 | */ 6 | var l,a;l=this,a=function(){"use strict";var l={},a={};try{"undefined"!=typeof window&&(l=window),"undefined"!=typeof document&&(a=document)}catch(l){}var e=(l.navigator||{}).userAgent,r=void 0===e?"":e,n=l,o=a,u=(n.document,!!o.documentElement&&!!o.head&&"function"==typeof o.addEventListener&&o.createElement,~r.indexOf("MSIE")||r.indexOf("Trident/"),"___FONT_AWESOME___"),t=function(){try{return"production"===process.env.NODE_ENV}catch(l){return!1}}();var f=n||{};f[u]||(f[u]={}),f[u].styles||(f[u].styles={}),f[u].hooks||(f[u].hooks={}),f[u].shims||(f[u].shims=[]);var i=f[u],s=[["glass",null,"glass-martini"],["meetup","fab",null],["star-o","far","star"],["remove",null,"times"],["close",null,"times"],["gear",null,"cog"],["trash-o","far","trash-alt"],["file-o","far","file"],["clock-o","far","clock"],["arrow-circle-o-down","far","arrow-alt-circle-down"],["arrow-circle-o-up","far","arrow-alt-circle-up"],["play-circle-o","far","play-circle"],["repeat",null,"redo"],["rotate-right",null,"redo"],["refresh",null,"sync"],["list-alt","far",null],["dedent",null,"outdent"],["video-camera",null,"video"],["picture-o","far","image"],["photo","far","image"],["image","far","image"],["pencil",null,"pencil-alt"],["map-marker",null,"map-marker-alt"],["pencil-square-o","far","edit"],["share-square-o","far","share-square"],["check-square-o","far","check-square"],["arrows",null,"arrows-alt"],["times-circle-o","far","times-circle"],["check-circle-o","far","check-circle"],["mail-forward",null,"share"],["expand",null,"expand-alt"],["compress",null,"compress-alt"],["eye","far",null],["eye-slash","far",null],["warning",null,"exclamation-triangle"],["calendar",null,"calendar-alt"],["arrows-v",null,"arrows-alt-v"],["arrows-h",null,"arrows-alt-h"],["bar-chart","far","chart-bar"],["bar-chart-o","far","chart-bar"],["twitter-square","fab",null],["facebook-square","fab",null],["gears",null,"cogs"],["thumbs-o-up","far","thumbs-up"],["thumbs-o-down","far","thumbs-down"],["heart-o","far","heart"],["sign-out",null,"sign-out-alt"],["linkedin-square","fab","linkedin"],["thumb-tack",null,"thumbtack"],["external-link",null,"external-link-alt"],["sign-in",null,"sign-in-alt"],["github-square","fab",null],["lemon-o","far","lemon"],["square-o","far","square"],["bookmark-o","far","bookmark"],["twitter","fab",null],["facebook","fab","facebook-f"],["facebook-f","fab","facebook-f"],["github","fab",null],["credit-card","far",null],["feed",null,"rss"],["hdd-o","far","hdd"],["hand-o-right","far","hand-point-right"],["hand-o-left","far","hand-point-left"],["hand-o-up","far","hand-point-up"],["hand-o-down","far","hand-point-down"],["arrows-alt",null,"expand-arrows-alt"],["group",null,"users"],["chain",null,"link"],["scissors",null,"cut"],["files-o","far","copy"],["floppy-o","far","save"],["navicon",null,"bars"],["reorder",null,"bars"],["pinterest","fab",null],["pinterest-square","fab",null],["google-plus-square","fab",null],["google-plus","fab","google-plus-g"],["money","far","money-bill-alt"],["unsorted",null,"sort"],["sort-desc",null,"sort-down"],["sort-asc",null,"sort-up"],["linkedin","fab","linkedin-in"],["rotate-left",null,"undo"],["legal",null,"gavel"],["tachometer",null,"tachometer-alt"],["dashboard",null,"tachometer-alt"],["comment-o","far","comment"],["comments-o","far","comments"],["flash",null,"bolt"],["clipboard","far",null],["paste","far","clipboard"],["lightbulb-o","far","lightbulb"],["exchange",null,"exchange-alt"],["cloud-download",null,"cloud-download-alt"],["cloud-upload",null,"cloud-upload-alt"],["bell-o","far","bell"],["cutlery",null,"utensils"],["file-text-o","far","file-alt"],["building-o","far","building"],["hospital-o","far","hospital"],["tablet",null,"tablet-alt"],["mobile",null,"mobile-alt"],["mobile-phone",null,"mobile-alt"],["circle-o","far","circle"],["mail-reply",null,"reply"],["github-alt","fab",null],["folder-o","far","folder"],["folder-open-o","far","folder-open"],["smile-o","far","smile"],["frown-o","far","frown"],["meh-o","far","meh"],["keyboard-o","far","keyboard"],["flag-o","far","flag"],["mail-reply-all",null,"reply-all"],["star-half-o","far","star-half"],["star-half-empty","far","star-half"],["star-half-full","far","star-half"],["code-fork",null,"code-branch"],["chain-broken",null,"unlink"],["shield",null,"shield-alt"],["calendar-o","far","calendar"],["maxcdn","fab",null],["html5","fab",null],["css3","fab",null],["ticket",null,"ticket-alt"],["minus-square-o","far","minus-square"],["level-up",null,"level-up-alt"],["level-down",null,"level-down-alt"],["pencil-square",null,"pen-square"],["external-link-square",null,"external-link-square-alt"],["compass","far",null],["caret-square-o-down","far","caret-square-down"],["toggle-down","far","caret-square-down"],["caret-square-o-up","far","caret-square-up"],["toggle-up","far","caret-square-up"],["caret-square-o-right","far","caret-square-right"],["toggle-right","far","caret-square-right"],["eur",null,"euro-sign"],["euro",null,"euro-sign"],["gbp",null,"pound-sign"],["usd",null,"dollar-sign"],["dollar",null,"dollar-sign"],["inr",null,"rupee-sign"],["rupee",null,"rupee-sign"],["jpy",null,"yen-sign"],["cny",null,"yen-sign"],["rmb",null,"yen-sign"],["yen",null,"yen-sign"],["rub",null,"ruble-sign"],["ruble",null,"ruble-sign"],["rouble",null,"ruble-sign"],["krw",null,"won-sign"],["won",null,"won-sign"],["btc","fab",null],["bitcoin","fab","btc"],["file-text",null,"file-alt"],["sort-alpha-asc",null,"sort-alpha-down"],["sort-alpha-desc",null,"sort-alpha-down-alt"],["sort-amount-asc",null,"sort-amount-down"],["sort-amount-desc",null,"sort-amount-down-alt"],["sort-numeric-asc",null,"sort-numeric-down"],["sort-numeric-desc",null,"sort-numeric-down-alt"],["youtube-square","fab",null],["youtube","fab",null],["xing","fab",null],["xing-square","fab",null],["youtube-play","fab","youtube"],["dropbox","fab",null],["stack-overflow","fab",null],["instagram","fab",null],["flickr","fab",null],["adn","fab",null],["bitbucket","fab",null],["bitbucket-square","fab","bitbucket"],["tumblr","fab",null],["tumblr-square","fab",null],["long-arrow-down",null,"long-arrow-alt-down"],["long-arrow-up",null,"long-arrow-alt-up"],["long-arrow-left",null,"long-arrow-alt-left"],["long-arrow-right",null,"long-arrow-alt-right"],["apple","fab",null],["windows","fab",null],["android","fab",null],["linux","fab",null],["dribbble","fab",null],["skype","fab",null],["foursquare","fab",null],["trello","fab",null],["gratipay","fab",null],["gittip","fab","gratipay"],["sun-o","far","sun"],["moon-o","far","moon"],["vk","fab",null],["weibo","fab",null],["renren","fab",null],["pagelines","fab",null],["stack-exchange","fab",null],["arrow-circle-o-right","far","arrow-alt-circle-right"],["arrow-circle-o-left","far","arrow-alt-circle-left"],["caret-square-o-left","far","caret-square-left"],["toggle-left","far","caret-square-left"],["dot-circle-o","far","dot-circle"],["vimeo-square","fab",null],["try",null,"lira-sign"],["turkish-lira",null,"lira-sign"],["plus-square-o","far","plus-square"],["slack","fab",null],["wordpress","fab",null],["openid","fab",null],["institution",null,"university"],["bank",null,"university"],["mortar-board",null,"graduation-cap"],["yahoo","fab",null],["google","fab",null],["reddit","fab",null],["reddit-square","fab",null],["stumbleupon-circle","fab",null],["stumbleupon","fab",null],["delicious","fab",null],["digg","fab",null],["pied-piper-pp","fab",null],["pied-piper-alt","fab",null],["drupal","fab",null],["joomla","fab",null],["spoon",null,"utensil-spoon"],["behance","fab",null],["behance-square","fab",null],["steam","fab",null],["steam-square","fab",null],["automobile",null,"car"],["envelope-o","far","envelope"],["spotify","fab",null],["deviantart","fab",null],["soundcloud","fab",null],["file-pdf-o","far","file-pdf"],["file-word-o","far","file-word"],["file-excel-o","far","file-excel"],["file-powerpoint-o","far","file-powerpoint"],["file-image-o","far","file-image"],["file-photo-o","far","file-image"],["file-picture-o","far","file-image"],["file-archive-o","far","file-archive"],["file-zip-o","far","file-archive"],["file-audio-o","far","file-audio"],["file-sound-o","far","file-audio"],["file-video-o","far","file-video"],["file-movie-o","far","file-video"],["file-code-o","far","file-code"],["vine","fab",null],["codepen","fab",null],["jsfiddle","fab",null],["life-ring","far",null],["life-bouy","far","life-ring"],["life-buoy","far","life-ring"],["life-saver","far","life-ring"],["support","far","life-ring"],["circle-o-notch",null,"circle-notch"],["rebel","fab",null],["ra","fab","rebel"],["resistance","fab","rebel"],["empire","fab",null],["ge","fab","empire"],["git-square","fab",null],["git","fab",null],["hacker-news","fab",null],["y-combinator-square","fab","hacker-news"],["yc-square","fab","hacker-news"],["tencent-weibo","fab",null],["qq","fab",null],["weixin","fab",null],["wechat","fab","weixin"],["send",null,"paper-plane"],["paper-plane-o","far","paper-plane"],["send-o","far","paper-plane"],["circle-thin","far","circle"],["header",null,"heading"],["sliders",null,"sliders-h"],["futbol-o","far","futbol"],["soccer-ball-o","far","futbol"],["slideshare","fab",null],["twitch","fab",null],["yelp","fab",null],["newspaper-o","far","newspaper"],["paypal","fab",null],["google-wallet","fab",null],["cc-visa","fab",null],["cc-mastercard","fab",null],["cc-discover","fab",null],["cc-amex","fab",null],["cc-paypal","fab",null],["cc-stripe","fab",null],["bell-slash-o","far","bell-slash"],["trash",null,"trash-alt"],["copyright","far",null],["eyedropper",null,"eye-dropper"],["area-chart",null,"chart-area"],["pie-chart",null,"chart-pie"],["line-chart",null,"chart-line"],["lastfm","fab",null],["lastfm-square","fab",null],["ioxhost","fab",null],["angellist","fab",null],["cc","far","closed-captioning"],["ils",null,"shekel-sign"],["shekel",null,"shekel-sign"],["sheqel",null,"shekel-sign"],["meanpath","fab","font-awesome"],["buysellads","fab",null],["connectdevelop","fab",null],["dashcube","fab",null],["forumbee","fab",null],["leanpub","fab",null],["sellsy","fab",null],["shirtsinbulk","fab",null],["simplybuilt","fab",null],["skyatlas","fab",null],["diamond","far","gem"],["intersex",null,"transgender"],["facebook-official","fab","facebook"],["pinterest-p","fab",null],["whatsapp","fab",null],["hotel",null,"bed"],["viacoin","fab",null],["medium","fab",null],["y-combinator","fab",null],["yc","fab","y-combinator"],["optin-monster","fab",null],["opencart","fab",null],["expeditedssl","fab",null],["battery-4",null,"battery-full"],["battery",null,"battery-full"],["battery-3",null,"battery-three-quarters"],["battery-2",null,"battery-half"],["battery-1",null,"battery-quarter"],["battery-0",null,"battery-empty"],["object-group","far",null],["object-ungroup","far",null],["sticky-note-o","far","sticky-note"],["cc-jcb","fab",null],["cc-diners-club","fab",null],["clone","far",null],["hourglass-o","far","hourglass"],["hourglass-1",null,"hourglass-start"],["hourglass-2",null,"hourglass-half"],["hourglass-3",null,"hourglass-end"],["hand-rock-o","far","hand-rock"],["hand-grab-o","far","hand-rock"],["hand-paper-o","far","hand-paper"],["hand-stop-o","far","hand-paper"],["hand-scissors-o","far","hand-scissors"],["hand-lizard-o","far","hand-lizard"],["hand-spock-o","far","hand-spock"],["hand-pointer-o","far","hand-pointer"],["hand-peace-o","far","hand-peace"],["registered","far",null],["creative-commons","fab",null],["gg","fab",null],["gg-circle","fab",null],["tripadvisor","fab",null],["odnoklassniki","fab",null],["odnoklassniki-square","fab",null],["get-pocket","fab",null],["wikipedia-w","fab",null],["safari","fab",null],["chrome","fab",null],["firefox","fab",null],["opera","fab",null],["internet-explorer","fab",null],["television",null,"tv"],["contao","fab",null],["500px","fab",null],["amazon","fab",null],["calendar-plus-o","far","calendar-plus"],["calendar-minus-o","far","calendar-minus"],["calendar-times-o","far","calendar-times"],["calendar-check-o","far","calendar-check"],["map-o","far","map"],["commenting",null,"comment-dots"],["commenting-o","far","comment-dots"],["houzz","fab",null],["vimeo","fab","vimeo-v"],["black-tie","fab",null],["fonticons","fab",null],["reddit-alien","fab",null],["edge","fab",null],["credit-card-alt",null,"credit-card"],["codiepie","fab",null],["modx","fab",null],["fort-awesome","fab",null],["usb","fab",null],["product-hunt","fab",null],["mixcloud","fab",null],["scribd","fab",null],["pause-circle-o","far","pause-circle"],["stop-circle-o","far","stop-circle"],["bluetooth","fab",null],["bluetooth-b","fab",null],["gitlab","fab",null],["wpbeginner","fab",null],["wpforms","fab",null],["envira","fab",null],["wheelchair-alt","fab","accessible-icon"],["question-circle-o","far","question-circle"],["volume-control-phone",null,"phone-volume"],["asl-interpreting",null,"american-sign-language-interpreting"],["deafness",null,"deaf"],["hard-of-hearing",null,"deaf"],["glide","fab",null],["glide-g","fab",null],["signing",null,"sign-language"],["viadeo","fab",null],["viadeo-square","fab",null],["snapchat","fab",null],["snapchat-ghost","fab",null],["snapchat-square","fab",null],["pied-piper","fab",null],["first-order","fab",null],["yoast","fab",null],["themeisle","fab",null],["google-plus-official","fab","google-plus"],["google-plus-circle","fab","google-plus"],["font-awesome","fab",null],["fa","fab","font-awesome"],["handshake-o","far","handshake"],["envelope-open-o","far","envelope-open"],["linode","fab",null],["address-book-o","far","address-book"],["vcard",null,"address-card"],["address-card-o","far","address-card"],["vcard-o","far","address-card"],["user-circle-o","far","user-circle"],["user-o","far","user"],["id-badge","far",null],["drivers-license",null,"id-card"],["id-card-o","far","id-card"],["drivers-license-o","far","id-card"],["quora","fab",null],["free-code-camp","fab",null],["telegram","fab",null],["thermometer-4",null,"thermometer-full"],["thermometer",null,"thermometer-full"],["thermometer-3",null,"thermometer-three-quarters"],["thermometer-2",null,"thermometer-half"],["thermometer-1",null,"thermometer-quarter"],["thermometer-0",null,"thermometer-empty"],["bathtub",null,"bath"],["s15",null,"bath"],["window-maximize","far",null],["window-restore","far",null],["times-rectangle",null,"window-close"],["window-close-o","far","window-close"],["times-rectangle-o","far","window-close"],["bandcamp","fab",null],["grav","fab",null],["etsy","fab",null],["imdb","fab",null],["ravelry","fab",null],["eercast","fab","sellcast"],["snowflake-o","far","snowflake"],["superpowers","fab",null],["wpexplorer","fab",null],["cab",null,"taxi"]];return function(l){try{l()}catch(l){if(!t)throw l}}(function(){var l;"function"==typeof i.hooks.addShims?i.hooks.addShims(s):(l=i.shims).push.apply(l,s)}),s},"object"==typeof exports&&"undefined"!=typeof module?module.exports=a():"function"==typeof define&&define.amd?define(a):l["fontawesome-free-shims"]=a(); 7 | -------------------------------------------------------------------------------- /admin/src/components/GrapesEditor/assets/scss/_variables.scss: -------------------------------------------------------------------------------- 1 | $primaryColor: #292B2C; 2 | $secondaryColor: #ddd; 3 | $tertiaryColor: #012f85; 4 | $quaternaryColor: #0097f7; 5 | 6 | $leftWidth: 25%; 7 | $fontSize: 1.5rem; 8 | $fontSizeS: 1.5rem; 9 | $canvasTop: 50px; 10 | -------------------------------------------------------------------------------- /admin/src/components/GrapesEditor/assets/scss/grapes_main.scss: -------------------------------------------------------------------------------- 1 | /* 2 | This file replicates content of grapesjs/src/styles/scss/main.scss 3 | 4 | Because of known issue, importing original file results in compilation failure 5 | See this comment: https://github.com/artf/grapesjs/commit/6aa1828a6246c092b6a47585be68f57cd4381501#commitcomment-40021489 6 | */ 7 | 8 | @import '~spectrum-colorpicker/spectrum'; 9 | @import '~codemirror/lib/codemirror'; 10 | @import '~codemirror/theme/hopscotch'; 11 | @import '~grapesjs/src/styles/scss/gjs_variables.scss'; 12 | @font-face { 13 | font-family: 'font3336'; 14 | src: url('#{$fontPath}/#{$fontName}.eot?v=#{$fontV}'); 15 | src: url('#{$fontPath}/#{$fontName}.woff?v=#{$fontV}') format('woff'), //url('#{$fontPath}/#{$fontName}.woff2?v=#{$fontV}') format('woff2'), 16 | url('#{$fontPath}/#{$fontName}.ttf?v=#{$fontV}') format('truetype'), 17 | url('#{$fontPath}/#{$fontName}.svg?v=#{$fontV}') format('svg'), 18 | url('#{$fontPath}/#{$fontName}.eot?v=#{$fontV}') format('embedded-opentype'); 19 | font-weight: normal; 20 | font-style: normal; 21 | } 22 | 23 | @mixin user-select($v) { 24 | -moz-user-select: $v; 25 | -khtml-user-select: $v; 26 | -webkit-user-select: $v; 27 | -ms-user-select: $v; 28 | -o-user-select: $v; 29 | user-select: $v; 30 | } 31 | 32 | @mixin opacity($v) { 33 | opacity: $v; 34 | filter: alpha(opacity=$v * 100); 35 | } 36 | 37 | @mixin appearance($v) { 38 | -webkit-appearance: $v; 39 | -moz-appearance: $v; 40 | appearance: $v; 41 | } 42 | 43 | @mixin transform($v) { 44 | -ms-transform: $v; 45 | -webkit-transform: $v; 46 | -moz-transform: $v; 47 | transform: $v; 48 | } 49 | 50 | $prefix: $app-prefix; 51 | @import '~grapesjs/src/styles/scss/gjs_status'; 52 | $colorsAll: (one, 53 | $primaryColor), 54 | (two, 55 | $secondaryColor), 56 | (three, 57 | $tertiaryColor), 58 | (four, 59 | $quaternaryColor), 60 | (danger, 61 | $colorRed); 62 | .#{$prefix} { 63 | @each $cnum, 64 | $ccol in $colorsAll { 65 | &#{$cnum} { 66 | &-bg { 67 | background-color: $ccol; 68 | } 69 | &-color { 70 | color: $ccol; 71 | &-h:hover { 72 | color: $ccol; 73 | } 74 | } 75 | } 76 | } 77 | } 78 | 79 | .#{$app-prefix}bg { 80 | &-main { 81 | background-color: $mainColor; 82 | } 83 | } 84 | 85 | .#{$app-prefix}color { 86 | &-main { 87 | color: $fontColor; 88 | fill: $fontColor; 89 | } 90 | &-active { 91 | color: $fontColorActive; 92 | fill: $fontColorActive; 93 | } 94 | &-warn { 95 | color: $colorWarn; 96 | fill: $colorWarn; 97 | } 98 | &-hl { 99 | color: $colorHighlight; 100 | fill: $colorHighlight; 101 | } 102 | } 103 | 104 | .#{$app-prefix}fonts::before { 105 | display: block; 106 | font: normal normal normal 14px font3336; // shortening font declaration 107 | text-rendering: auto; // optimizelegibility throws things off #1094 108 | -webkit-font-smoothing: antialiased; 109 | -moz-osx-font-smoothing: grayscale; 110 | font-size: 5em; 111 | } 112 | 113 | .#{$app-prefix}f-b1::before { 114 | content: 'Q'; 115 | } 116 | 117 | .#{$app-prefix}f-b2::before { 118 | content: 'W'; 119 | } 120 | 121 | .#{$app-prefix}f-b3::before { 122 | content: 'E'; 123 | } 124 | 125 | .#{$app-prefix}f-b37::before { 126 | content: 'R'; 127 | } 128 | 129 | .#{$app-prefix}f-hero::before { 130 | content: 'T'; 131 | } 132 | 133 | .#{$app-prefix}f-h1p::before { 134 | content: 'y'; 135 | } 136 | 137 | .#{$app-prefix}f-3ba::before { 138 | content: 'u'; 139 | } 140 | 141 | .#{$app-prefix}f-image::before { 142 | content: 'I'; 143 | } 144 | 145 | .#{$app-prefix}f-text::before { 146 | content: 'o'; 147 | } 148 | 149 | .#{$app-prefix}f-quo::before { 150 | content: 'p'; 151 | } 152 | 153 | .#{$app-prefix}f-button::before { 154 | content: 'B'; 155 | } 156 | 157 | .#{$app-prefix}f-divider::before { 158 | content: 'D'; 159 | } 160 | 161 | .#{$app-prefix}invis-invis, 162 | .#{$app-prefix}no-app { 163 | background-color: transparent; 164 | border: none; 165 | color: inherit; 166 | } 167 | 168 | .#{$app-prefix}no-app { 169 | height: 10px; 170 | } 171 | 172 | .#{$app-prefix}test { 173 | &::btn { 174 | color: '#fff'; 175 | } 176 | &input {} 177 | &header {} 178 | } 179 | 180 | .opac50 { 181 | @include opacity(0.5); 182 | } 183 | 184 | .#{$app-prefix}checker-bg, 185 | .checker-bg { 186 | background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg=='); 187 | } 188 | 189 | .#{$app-prefix}no-user-select { 190 | @include user-select(none); 191 | } 192 | 193 | .#{$app-prefix}no-pointer-events { 194 | pointer-events: none; 195 | } 196 | 197 | .#{$app-prefix}bdrag { 198 | pointer-events: none !important; 199 | position: absolute !important; 200 | z-index: 10 !important; 201 | width: auto; 202 | } 203 | 204 | .#{$app-prefix}drag-helper { 205 | background-color: $colorBlue !important; 206 | pointer-events: none !important; 207 | position: absolute !important; 208 | z-index: 10 !important; 209 | transform: scale(0.3) !important; 210 | transform-origin: top left !important; 211 | -webkit-transform-origin: top left !important; 212 | margin: 15px !important; 213 | transition: none !important; 214 | outline: none !important; 215 | } 216 | 217 | .#{$app-prefix}grabbing, 218 | .#{$app-prefix}grabbing * { 219 | @extend .#{$app-prefix}no-user-select; 220 | cursor: grabbing !important; 221 | cursor: -webkit-grabbing !important; 222 | } 223 | 224 | .#{$app-prefix}grabbing { 225 | overflow: hidden; 226 | } 227 | 228 | .#{$app-prefix}off-prv { 229 | @extend .#{$app-prefix}color-main; 230 | @extend .#{$app-prefix}bg-main; 231 | position: relative; 232 | z-index: 10; 233 | padding: 5px; 234 | cursor: pointer; 235 | } 236 | 237 | // Custom scrollbars for Chrome 238 | .#{$app-prefix}editor-cont ::-webkit-scrollbar-track { 239 | background: $mainDklColor; 240 | } 241 | 242 | .#{$app-prefix}editor-cont ::-webkit-scrollbar-thumb { 243 | background-color: rgba(255, 255, 255, 0.2); 244 | } 245 | 246 | .#{$app-prefix}editor-cont ::-webkit-scrollbar { 247 | width: 8px; 248 | } 249 | 250 | 251 | /********************* MAIN ************************/ 252 | 253 | .clear { 254 | clear: both; 255 | } 256 | 257 | .no-select { 258 | @include user-select(none); 259 | } 260 | 261 | .#{$app-prefix} { 262 | &no-touch-actions { 263 | touch-action: none; 264 | } 265 | &disabled { 266 | @include user-select(none); 267 | @include opacity(0.5); 268 | } 269 | &editor { 270 | font-family: $mainFont; 271 | font-size: $fontSizeS; 272 | position: relative; 273 | box-sizing: border-box; 274 | height: 100%; 275 | } 276 | } 277 | 278 | .#{$app-prefix}freezed, 279 | .#{$nv-prefix}freezed { 280 | @include opacity(0.5); 281 | pointer-events: none; 282 | } 283 | 284 | @import '~grapesjs/src/styles/scss/gjs_traits'; 285 | @import '~grapesjs/src/styles/scss/gjs_canvas'; 286 | 287 | /********* COMMANDS **********/ 288 | 289 | .no-dots, 290 | .ui-resizable-handle { 291 | border: none !important; 292 | margin: 0 !important; 293 | outline: none !important; 294 | } 295 | 296 | .#{$com-prefix}dashed * { 297 | outline: 1px dashed #888; 298 | outline-offset: -2px; 299 | box-sizing: border-box; 300 | } 301 | 302 | .#{$com-prefix}no-select, 303 | .#{$com-prefix}no-select img { 304 | @extend .no-select; 305 | } 306 | 307 | .#{$cv-prefix}canvas .#{$comp-prefix}selected { 308 | //TODO 309 | outline: 3px solid $colorBlue !important; 310 | } 311 | 312 | *.#{$com-prefix}hover, 313 | div.#{$com-prefix}hover { 314 | outline: 1px solid $colorBlue; 315 | } 316 | 317 | *.#{$com-prefix}hover-delete, 318 | div.#{$com-prefix}hover-delete { 319 | outline: 2px solid $colorRed; 320 | @include opacity(0.5); 321 | } 322 | 323 | *.#{$com-prefix}hover-move, 324 | div.#{$com-prefix}hover-move { 325 | outline: 3px solid $colorYell; 326 | } 327 | 328 | .#{$com-prefix}badge, 329 | .#{$app-prefix}badge { 330 | pointer-events: none; 331 | background-color: $colorBlue; 332 | color: #fff; 333 | padding: 2px 5px; 334 | position: absolute; 335 | z-index: 1; 336 | font-size: 12px; 337 | outline: none; 338 | display: none; 339 | } 340 | 341 | .#{$com-prefix}badge-red { 342 | @extend .#{$com-prefix}badge; 343 | background-color: $colorRed; 344 | } 345 | 346 | .#{$app-prefix}badge-warning { 347 | background-color: $colorYell; 348 | } 349 | 350 | .#{$app-prefix}placeholder, 351 | .#{$com-prefix}placeholder, 352 | .#{$nv-prefix}placeholder { 353 | position: absolute; 354 | z-index: 10; 355 | pointer-events: none; 356 | display: none; 357 | } 358 | 359 | .#{$app-prefix}placeholder, 360 | .#{$nv-prefix}placeholder { 361 | border-style: solid !important; 362 | outline: none; 363 | box-sizing: border-box; 364 | transition: top $animSpeed, left $animSpeed, width $animSpeed, height $animSpeed; 365 | } 366 | 367 | .#{$app-prefix}placeholder.horizontal, 368 | .#{$com-prefix}placeholder.horizontal, 369 | .#{$nv-prefix}placeholder.horizontal { 370 | border-color: transparent $placeholderColor; 371 | border-width: 3px 5px; 372 | margin: -3px 0 0; 373 | } 374 | 375 | .#{$app-prefix}placeholder.vertical, 376 | .#{$com-prefix}placeholder.vertical, 377 | .#{$nv-prefix}placeholder.vertical { 378 | border-color: $placeholderColor transparent; 379 | border-width: 5px 3px; 380 | margin: 0 0 0 -3px; 381 | } 382 | 383 | .#{$app-prefix}placeholder-int, 384 | .#{$com-prefix}placeholder-int, 385 | .#{$nv-prefix}placeholder-int { 386 | background-color: $placeholderColor; 387 | box-shadow: 0 0 3px rgba(0, 0, 0, 0.2); 388 | height: 100%; 389 | width: 100%; 390 | pointer-events: none; 391 | padding: 1.5px; 392 | outline: none; 393 | } 394 | 395 | @import '~grapesjs/src/styles/scss/gjs_panels'; 396 | 397 | /*********** Components *************/ 398 | 399 | .#{$comp-prefix}image-placeholder { 400 | display: block; 401 | background-color: #f5f5f5; 402 | color: $fontColorDk; 403 | height: $imageCompDim; 404 | width: $imageCompDim; 405 | line-height: $imageCompDim; 406 | outline: 3px solid $colorYell; 407 | outline-offset: -3px; 408 | text-align: center; 409 | font-size: $imageCompDim/3; 410 | cursor: pointer; 411 | &.fa-picture-o::after { 412 | content: '\f03e'; 413 | } 414 | } 415 | 416 | @import '~grapesjs/src/styles/scss/gjs_inputs'; 417 | @import '~grapesjs/src/styles/scss/gjs_devices'; 418 | 419 | /********* General **********/ 420 | 421 | .#{$app-prefix}category-open { 422 | border-bottom: 1px solid rgba(0, 0, 0, 0.25); 423 | } 424 | 425 | .#{$app-prefix}category-title { 426 | @extend .no-select; 427 | font-weight: lighter; 428 | background-color: $mainDklColor; 429 | letter-spacing: 1px; 430 | padding: 9px 10px 9px 20px; 431 | border-bottom: 1px solid rgba(0, 0, 0, 0.25); 432 | text-align: left; 433 | position: relative; 434 | cursor: pointer; 435 | } 436 | 437 | @import '~grapesjs/src/styles/scss/gjs_style_manager'; 438 | @import '~grapesjs/src/styles/scss/gjs_blocks'; 439 | @import '~grapesjs/src/styles/scss/gjs_layers'; 440 | @import '~grapesjs/src/styles/scss/gjs_selectors'; 441 | @import '~grapesjs/src/styles/scss/gjs_modal'; 442 | @import '~grapesjs/src/styles/scss/gjs_assets'; 443 | 444 | /********* File uploader **********/ 445 | 446 | .#{$am-prefix}file-uploader { 447 | width: 55%; 448 | float: left; 449 | >form { 450 | background-color: $mainDklColor; 451 | border: 2px dashed; 452 | border-radius: 3px; 453 | position: relative; 454 | text-align: center; 455 | margin-bottom: 15px; 456 | &.#{$am-prefix}hover { 457 | border: 2px solid $colorGreen; 458 | color: lighten($colorGreen, 5%); 459 | /*#7ee07e*/ 460 | } 461 | &.#{$am-prefix}disabled { 462 | border-color: red; 463 | } 464 | ##{$am-prefix}uploadFile { 465 | @include opacity(0); 466 | padding: $uploadPadding; 467 | width: 100%; 468 | box-sizing: border-box; 469 | } 470 | } 471 | ##{$am-prefix}title { 472 | position: absolute; 473 | padding: $uploadPadding; 474 | width: 100%; 475 | } 476 | } 477 | 478 | 479 | /********* Code Manager **********/ 480 | 481 | .#{$cm-prefix}editor-c { 482 | float: left; 483 | box-sizing: border-box; 484 | width: 50%; 485 | .CodeMirror { 486 | height: 450px; 487 | } 488 | } 489 | 490 | .#{$cm-prefix}editor { 491 | font-size: 12px; 492 | &##{$cm-prefix}htmlmixed { 493 | padding-right: 10px; 494 | border-right: 1px solid $mainDkColor; 495 | ##{$cm-prefix}title { 496 | color: #a97d44; 497 | } 498 | } 499 | &##{$cm-prefix}css { 500 | padding-left: 10px; 501 | ##{$cm-prefix}title { 502 | color: #ddca7e; 503 | } 504 | } 505 | ##{$cm-prefix}title { 506 | background-color: $mainDkColor; 507 | font-size: 12px; 508 | padding: 5px 10px 3px; 509 | text-align: right; 510 | } 511 | } 512 | 513 | 514 | /*************RTE****************/ 515 | 516 | @import '~grapesjs/src/styles/scss/gjs_rte'; 517 | 518 | /********* Spectrum **********/ 519 | 520 | .#{$app-prefix}editor-cont { 521 | .sp-hue, 522 | .sp-slider { 523 | cursor: row-resize; 524 | } 525 | .sp-color, 526 | .sp-dragger { 527 | cursor: crosshair; 528 | } 529 | .sp-alpha-inner, 530 | .sp-alpha-handle { 531 | cursor: col-resize; 532 | } 533 | .sp-hue { 534 | left: 90%; 535 | } 536 | .sp-color { 537 | right: 15%; 538 | } 539 | .sp-container { 540 | border: 1px solid $mainDkColor; 541 | box-shadow: 0 0 7px $mainDkColor; 542 | border-radius: 3px; 543 | } 544 | .sp-picker-container { 545 | border: none; 546 | } 547 | .colpick_dark .colpick_color { 548 | outline: 1px solid $mainDkColor; 549 | } 550 | .sp-cancel, 551 | .sp-cancel:hover { 552 | bottom: -8px; 553 | color: #777 !important; 554 | font-size: 25px; 555 | left: 0; 556 | position: absolute; 557 | text-decoration: none; 558 | } 559 | .sp-alpha-handle { 560 | background-color: #ccc; 561 | border: 1px solid #555; 562 | width: 4px; 563 | } 564 | .sp-color, 565 | .sp-hue { 566 | border: 1px solid #333333; 567 | } 568 | .sp-slider { 569 | background-color: #ccc; 570 | border: 1px solid #555; 571 | height: 3px; 572 | left: -4px; 573 | width: 22px; 574 | } 575 | .sp-dragger { 576 | background: transparent; 577 | box-shadow: 0 0 0 1px #111; 578 | } 579 | .sp-button-container { 580 | float: none; 581 | width: 100%; 582 | position: relative; 583 | text-align: right; 584 | } 585 | .sp-container button, 586 | .sp-container button:hover, 587 | .sp-container button:active { 588 | background: $mainDkColor; 589 | border-color: $mainDkColor; 590 | color: $fontColor; 591 | text-shadow: none; 592 | box-shadow: none; 593 | padding: 3px 5px; 594 | } 595 | .sp-palette-container { 596 | border: none; 597 | float: none; 598 | margin: 0; 599 | padding: 5px 10px 0; 600 | } 601 | .sp-palette .sp-thumb-el, 602 | .sp-palette .sp-thumb-el:hover { 603 | border: 1px solid rgba(0, 0, 0, 0.9); 604 | } 605 | .sp-palette .sp-thumb-el:hover, 606 | .sp-palette .sp-thumb-el.sp-thumb-active { 607 | border-color: rgba(0, 0, 0, 0.9); 608 | } 609 | } 610 | 611 | .#{$app-prefix}hidden { 612 | display: none; 613 | } 614 | 615 | @keyframes #{$app-prefix}slide-down { 616 | 0% { 617 | transform: translate(0, -3rem); 618 | opacity: 0; 619 | } 620 | 100% { 621 | transform: translate(0, 0); 622 | opacity: 1; 623 | } 624 | } 625 | 626 | @keyframes #{$app-prefix}slide-up { 627 | 0% { 628 | transform: translate(0, 0); 629 | opacity: 1; 630 | } 631 | 100% { 632 | transform: translate(0, -3rem); 633 | opacity: 0; 634 | } 635 | } 636 | 637 | .cm-s-hopscotch span.cm-error { 638 | color: #ffffff; 639 | } -------------------------------------------------------------------------------- /admin/src/components/GrapesEditor/assets/scss/main.scss: -------------------------------------------------------------------------------- 1 | @import './variables'; 2 | @import './grapes_main.scss'; 3 | .gjs-block-label { 4 | font-size: 1rem; 5 | } 6 | 7 | // Layers list items height 8 | .gjs-no-app { 9 | height: 15px; 10 | } 11 | 12 | .gjs-devices-c { 13 | font-size: xx-small; 14 | } -------------------------------------------------------------------------------- /admin/src/components/GrapesEditor/config/device-manager.config.js: -------------------------------------------------------------------------------- 1 | export const deviceManagerConfig = { 2 | devices: [ 3 | { 4 | id: 'desktop', 5 | name: 'Desktop', 6 | width: '1200px', 7 | widthMedia: '5000px', 8 | }, 9 | { 10 | id: 'tablet', 11 | name: 'Tablet', 12 | width: '768px', 13 | widthMedia: '992px', 14 | }, 15 | { 16 | id: 'mobileLandscape', 17 | name: 'Mobile landscape', 18 | width: '568px', 19 | widthMedia: '768px', 20 | }, 21 | { 22 | id: 'mobilePortrait', 23 | name: 'Mobile portrait', 24 | width: '320px', 25 | widthMedia: '480px', 26 | }, 27 | ], 28 | }; 29 | -------------------------------------------------------------------------------- /admin/src/components/GrapesEditor/config/editor.config.js: -------------------------------------------------------------------------------- 1 | export const editorConfig = { 2 | clearStyles: true, 3 | // avoidDefaults: 1, 4 | protectedCss: '', 5 | baseCss: ` * { 6 | box-sizing: border-box; 7 | } 8 | html, body, [data-gjs-type=wrapper] { 9 | min-height: 100%; 10 | font-family: VanCondensedPro; 11 | } 12 | body { 13 | margin: 0; 14 | height: 100%; 15 | background-color: #ebebeb 16 | } 17 | [data-gjs-type=wrapper] { 18 | overflow: auto; 19 | overflow-x: scroll; 20 | } 21 | * ::-webkit-scrollbar-track { 22 | background: rgba(0, 0, 0, 0.1) 23 | } 24 | * ::-webkit-scrollbar-thumb { 25 | background: rgba(255, 255, 255, 0.2) 26 | } 27 | * ::-webkit-scrollbar { 28 | width: 10px 29 | }`, 30 | cssIcons: 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/css/all.min.css', 31 | noticeOnUnload: false, 32 | }; 33 | -------------------------------------------------------------------------------- /admin/src/components/GrapesEditor/config/storage-manager.config.js: -------------------------------------------------------------------------------- 1 | export const storageManagerConfig = { 2 | autosave: true, 3 | autoload: false, 4 | setStepsBeforeSave: 1, 5 | type: 'local', 6 | contentTypeJson: true, 7 | }; 8 | -------------------------------------------------------------------------------- /admin/src/components/GrapesEditor/config/style-manager.config.js: -------------------------------------------------------------------------------- 1 | export const styleManagerConfig = { 2 | sectors: [ 3 | { 4 | name: 'General', 5 | open: false, 6 | buildProps: ['float'], 7 | }, 8 | { 9 | name: 'Flex', 10 | open: false, 11 | buildProps: [ 12 | 'flex-direction', 13 | 'flex-wrap', 14 | 'justify-content', 15 | 'align-items', 16 | 'align-content', 17 | 'order', 18 | 'flex-basis', 19 | 'flex-grow', 20 | 'flex-shrink', 21 | 'align-self', 22 | ], 23 | }, 24 | { 25 | name: 'Dimension', 26 | open: false, 27 | buildProps: ['width', 'height', 'max-width', 'min-height', 'margin', 'padding'], 28 | }, 29 | { 30 | name: 'Typography', 31 | open: false, 32 | buildProps: ['font-size', 'font-family', 'letter-spacing', 'color', 'line-height', 'text-align'], 33 | properties: [ 34 | { 35 | property: 'font-weight', 36 | defaults: 'normal', 37 | list: [{ value: 'normal' }, { value: 'bold' }], 38 | }, 39 | { 40 | property: 'font-family', 41 | // defaults: 'VanCondensedPro', 42 | list: [{ value: 'VanCondensedPro' }, { value: 'VanCondensedPro-Bold' }], 43 | }, 44 | { 45 | property: 'text-align', 46 | list: [ 47 | { value: 'left', className: 'fa fa-align-left' }, 48 | { value: 'center', className: 'fa fa-align-center' }, 49 | { value: 'right', className: 'fa fa-align-right' }, 50 | { value: 'justify', className: 'fa fa-align-justify' }, 51 | ], 52 | }, 53 | ], 54 | }, 55 | { 56 | name: 'Decorations', 57 | open: false, 58 | buildProps: ['border-radius-c', 'background-color', 'border-radius', 'border', 'box-shadow', 'background'], 59 | }, 60 | ], 61 | }; 62 | -------------------------------------------------------------------------------- /admin/src/components/GrapesEditor/grapes-plugins/strapi/blocks.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Block appearing in the block section of grapesjs. Can be dragged onto the canvas to generate a StrapiBlock. 3 | */ 4 | 5 | import { strapiRef } from './consts'; 6 | 7 | export default function (editor, userOptions = {}) { 8 | const bm = editor.BlockManager; 9 | 10 | // These are the styles that are used in the components. 11 | // See component.js onRender(). 12 | // These styles will also appear in the template's css. 13 | // NOTE: only styles that have '.strapi-block' in them will be put into the template's css. 14 | const style = userOptions.defaultStyle 15 | ? `` 25 | : ''; 26 | 27 | bm.remove(strapiRef); 28 | 29 | bm.add(strapiRef, { 30 | label: 'Image', 31 | category: userOptions.blockLabel, 32 | attributes: { class: 'gjs-fonts gjs-f-image' }, 33 | content: ` 34 | 35 | ${style} 36 | `, 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /admin/src/components/GrapesEditor/grapes-plugins/strapi/components.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; // eslint-disable-line import/no-unresolved 2 | import ReactDOM from 'react-dom'; // eslint-disable-line import/no-unresolved 3 | import { strapiRef } from './consts'; 4 | import { StrapiImageBlock } from './image.block'; 5 | 6 | export default function (editor, userOptions = {}) { 7 | const editorDomComponents = editor.DomComponents; 8 | const defaultType = editorDomComponents.getType('default'); 9 | const defaultModel = defaultType.model; 10 | const defaultView = defaultType.view; 11 | 12 | editorDomComponents.addType(strapiRef, { 13 | model: defaultModel.extend( 14 | { 15 | defaults: { 16 | ...defaultModel.prototype.defaults, 17 | assetsManager: userOptions.assetsManager, 18 | reactComponentsManager: userOptions.reactComponentsManager, 19 | image: { 20 | url: userOptions.url, 21 | alternativeText: userOptions.alternativeText, 22 | src: userOptions.src, 23 | alt: userOptions.alt, 24 | strapiId: userOptions.strapiId, 25 | }, 26 | attributes: { 27 | class: 'strapi-block', 28 | src: userOptions.src, 29 | alt: userOptions.alt, 30 | }, 31 | droppable: false, 32 | editable: true, 33 | highlightable: true, 34 | selectable: true, 35 | hoverable: true, 36 | }, 37 | }, 38 | { 39 | isComponent(el) { 40 | if ( 41 | (el.getAttribute && el.getAttribute('data-gjs-type') === strapiRef) || 42 | (el.attributes && el.attributes['data-gjs-type'] === strapiRef) 43 | ) { 44 | return { 45 | type: strapiRef, 46 | }; 47 | } 48 | }, 49 | } 50 | ), 51 | 52 | view: defaultView.extend({ 53 | events: { 54 | dblclick: 'onActive', 55 | }, 56 | init() { 57 | // Listen to changes managed by the traits 58 | this.listenTo(this.model, '', this.handleChanges); 59 | }, 60 | handleChanges(e) { 61 | /// Force rerender of react element 62 | ReactDOM.unmountComponentAtNode(this.el); 63 | this.render(); 64 | }, 65 | onActive(ev) { 66 | this.model.attributes.assetsManager.open(this.model.ccid, this.model.attributes.image.strapiId); 67 | }, 68 | onRender({ el }) { 69 | // Generate the block that'll be show in canvas 70 | ReactDOM.render( 71 | , 72 | el 73 | ); 74 | }, 75 | }), 76 | }); 77 | } 78 | -------------------------------------------------------------------------------- /admin/src/components/GrapesEditor/grapes-plugins/strapi/consts.js: -------------------------------------------------------------------------------- 1 | // The strapi components reference name, ie. the block's name and the component's name 2 | export const strapiRef = 'strapi'; 3 | 4 | // The plugin's reference. Must be passed to 5 | export const strapiPluginRef = 'strapi-plugin'; 6 | -------------------------------------------------------------------------------- /admin/src/components/GrapesEditor/grapes-plugins/strapi/image.block.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; // eslint-disable-line import/no-unresolved 2 | 3 | export const StrapiImageBlock = ({ assetsManager, model, imgRef }) => { 4 | const [image, setImage] = useState({ 5 | src: 6 | model.attributes.image.src || 7 | 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIHZpZXdCb3g9IjAgMCAyNCAyNCIgc3R5bGU9ImZpbGw6IHJnYmEoMCwwLDAsMC4xNSk7IHRyYW5zZm9ybTogc2NhbGUoMC43NSkiPgogICAgICAgIDxwYXRoIGQ9Ik04LjUgMTMuNWwyLjUgMyAzLjUtNC41IDQuNSA2SDVtMTYgMVY1YTIgMiAwIDAgMC0yLTJINWMtMS4xIDAtMiAuOS0yIDJ2MTRjMCAxLjEuOSAyIDIgMmgxNGMxLjEgMCAyLS45IDItMnoiPjwvcGF0aD4KICAgICAgPC9zdmc+', 8 | alt: model.attributes.image.alt || 'Alt text', 9 | }); 10 | 11 | const [assetsManagerMounted, setAssetsManagerMounted] = useState(false); 12 | 13 | const onFilePickedCallback = (imageData) => { 14 | setImage(imageData); 15 | model.attributes.image = imageData; 16 | 17 | model.setAttributes({ src: imageData.src, alt: imageData.alt }); 18 | // data-highlightable="false" data-gjs-editable="false" data-gjs-removable="false" draggable="false" alt="${alternativeText}" style="max-width: '100%';" />`); 19 | }; 20 | 21 | useEffect(() => { 22 | if (!assetsManagerMounted && model) { 23 | // Be careful: if you pass the callback function without nesting 24 | // it in an object it will be executed directly 25 | assetsManager.onFilePicked(model.ccid, { call: onFilePickedCallback }); 26 | setAssetsManagerMounted(true); 27 | } 28 | }, [assetsManager, model]); 29 | 30 | useEffect(() => { 31 | imgRef.src = image.src; 32 | imgRef.alt = image.alt; 33 | }, [image]); 34 | 35 | return null; 36 | }; 37 | -------------------------------------------------------------------------------- /admin/src/components/GrapesEditor/grapes-plugins/strapi/index.js: -------------------------------------------------------------------------------- 1 | import grapesjs from 'grapesjs'; 2 | import loadComponents from './components'; 3 | import loadBlocks from './blocks'; 4 | import loadPanels from './panels'; 5 | 6 | import { strapiRef, strapiPluginRef } from './consts'; 7 | 8 | export default function addStrapiPlugin() { 9 | grapesjs.plugins.add(strapiPluginRef, (editor, userOptions = {}) => { 10 | const defaults = { 11 | blocks: [strapiRef], 12 | 13 | // Label in block 14 | blockLabel: 'Strapi', 15 | 16 | // Category in block 17 | blockCategory: 'Extra', 18 | 19 | // Default style 20 | defaultStyle: true, 21 | assetsManager: null, 22 | }; 23 | 24 | // Load defaults 25 | for (const name in defaults) { 26 | if (!(name in userOptions)) userOptions[name] = defaults[name]; 27 | } 28 | 29 | // Add components 30 | loadComponents(editor, userOptions); 31 | 32 | // Add components 33 | loadBlocks(editor, userOptions); 34 | 35 | // Load panels 36 | loadPanels(editor, userOptions); 37 | 38 | // Show the blocks panel by default 39 | editor.on('load', () => { 40 | const openBlocksPanel = editor.Panels.getButton('views', 'open-blocks'); 41 | openBlocksPanel && openBlocksPanel.set('active', 1); 42 | // editor.runCommand('open-blocks'); 43 | }); 44 | }); 45 | } 46 | -------------------------------------------------------------------------------- /admin/src/components/GrapesEditor/grapes-plugins/strapi/panels.js: -------------------------------------------------------------------------------- 1 | export default (editor, config) => { 2 | // Add any button like so 3 | // const editorPanels = editor.Panels; 4 | // editorPanels.addButton('options', { 5 | // id: loadHtmltemplate, 6 | // className: 'fa fa-bell', 7 | // command: (e) => e.runCommand('your-command'), 8 | // }); 9 | }; 10 | -------------------------------------------------------------------------------- /admin/src/components/GrapesEditor/index.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; // eslint-disable-line import/no-unresolved 2 | import PropTypes from 'prop-types'; 3 | import GrapesJS from 'grapesjs'; 4 | import gjsBasicBlocks from 'grapesjs-blocks-basic'; // eslint-disable-line no-unused-vars 5 | import { useStrapi, prefixFileUrlWithBackendUrl } from 'strapi-helper-plugin'; // eslint-disable-line import/no-unresolved 6 | import './assets/scss/main.scss'; 7 | import addStrapiPlugin from './grapes-plugins/strapi'; 8 | import { strapiPluginRef } from './grapes-plugins/strapi/consts'; 9 | import { deviceManagerConfig } from './config/device-manager.config'; 10 | import { styleManagerConfig } from './config/style-manager.config'; 11 | import { storageManagerConfig } from './config/storage-manager.config'; 12 | import { editorConfig } from './config/editor.config'; 13 | import './assets/js/fa-shim'; 14 | 15 | // DEV note: Many dependencies use FA 16 | // Grapes has an older version 17 | // Strapi* use newer version which wraps icons in svg element 18 | // Doing so breaks grapes' toolbar callbacks 19 | // This dirty argument is here to nest svg in original element 20 | // instead of just replacing 21 | window.FontAwesome.config.autoReplaceSvg = 'nest'; 22 | 23 | const Editor = ({ onChange, name, value }) => { 24 | const [mediaLibConfiguration, setMediaLibConfiguration] = useState({ open: false }); 25 | const toggleMediaLib = () => 26 | setMediaLibConfiguration((prev) => { 27 | return { ...prev, open: !prev.open }; 28 | }); 29 | const [editor, setEditor] = useState(); 30 | const [editorConfigured, setEditorConfigured] = useState(false); 31 | const [mounted, setMounted] = useState(false); 32 | const [pluginsLoaded, setPluginsLoaded] = useState(false); 33 | const [mediaLibPickedData, setMediaLibPickedData] = useState(null); 34 | const [onFilePickedListeners, setOnFilePickedListeners] = useState({}); 35 | const [sharedAssetsManager, setSharedAssetsManager] = useState(null); 36 | const { 37 | strapi: { 38 | componentApi: { getComponent }, 39 | }, 40 | } = useStrapi(); 41 | 42 | const MediaLibComponent = getComponent('media-library').Component; 43 | 44 | const onMediaLibInputChange = (localData) => { 45 | if (localData) { 46 | const { url } = localData; 47 | setMediaLibPickedData({ ...localData, url: prefixFileUrlWithBackendUrl(url) }); 48 | } 49 | }; 50 | 51 | const onMediaLibClosed = () => { 52 | if (mediaLibPickedData) { 53 | const { url, alternativeText, id } = mediaLibPickedData; 54 | 55 | if (onFilePickedListeners && url) { 56 | const registeredListener = onFilePickedListeners[mediaLibConfiguration.activeImageId]; 57 | 58 | if (registeredListener) { 59 | registeredListener.call({ src: url, alt: alternativeText, strapiId: id }); 60 | } 61 | } 62 | } 63 | 64 | setMediaLibConfiguration({ open: false }); 65 | 66 | setMediaLibPickedData(null); 67 | }; 68 | 69 | useEffect(() => { 70 | if (!pluginsLoaded) { 71 | addStrapiPlugin(); 72 | setPluginsLoaded(true); 73 | 74 | setSharedAssetsManager({ 75 | open: (blockId, galleryId) => { 76 | setMediaLibConfiguration({ open: true, activeImageId: blockId, selected: { id: galleryId } }); 77 | }, 78 | close: () => onMediaLibClosed(), 79 | onFilePicked: (fileId, cbk) => 80 | setOnFilePickedListeners((previousListeners) => { 81 | return { ...previousListeners, [fileId]: cbk }; 82 | }), 83 | }); 84 | } 85 | }, [setPluginsLoaded]); 86 | 87 | useEffect(() => { 88 | if (mounted || !pluginsLoaded || !sharedAssetsManager) { 89 | return; 90 | } 91 | 92 | // Original props here https://github.com/artf/grapesjs/blob/master/src/editor/config/config.js 93 | setEditor( 94 | GrapesJS.init({ 95 | container: '#gjs', 96 | height: '500px', 97 | width: 'auto', 98 | // Rendered data 99 | components: (value && value.components) || {}, 100 | style: (value && value.styles) || {}, 101 | storageManager: storageManagerConfig, 102 | plugins: ['gjs-blocks-basic', strapiPluginRef], 103 | pluginsOpts: { 104 | 'gjs-blocks-basic': { 105 | blocks: ['column1', 'column2', 'column3', 'column3-7', 'text'], 106 | category: 'Basic Blocks', 107 | flexGrid: true, 108 | }, 109 | [strapiPluginRef]: { 110 | assetsManager: sharedAssetsManager, 111 | }, 112 | }, 113 | wrapperIsBody: false, 114 | styleManager: styleManagerConfig, 115 | deviceManager: deviceManagerConfig, 116 | ...editorConfig, 117 | }) 118 | ); 119 | setMounted(true); 120 | }, [value, mounted, pluginsLoaded]); 121 | 122 | useEffect(() => { 123 | if (!mounted || editorConfigured) { 124 | return; 125 | } 126 | 127 | editor.setDevice('Desktop'); 128 | editor.Panels.removeButton('options', 'export-template'); 129 | 130 | editor.on('storage:store', function (e) { 131 | // When store is called, trigger strapi onChange callback 132 | 133 | onChange({ 134 | target: { 135 | name, 136 | value: { 137 | components: JSON.parse(e.components), 138 | styles: JSON.parse(e.styles), 139 | css: e.css, 140 | html: e.html, 141 | }, 142 | }, 143 | }); 144 | setEditorConfigured(true); 145 | }); 146 | }, [mounted, editor, editorConfigured, sharedAssetsManager]); 147 | 148 | return ( 149 |
cannot appear as a descendant of ." 158 | onSubmit={(evt) => { 159 | evt.stopPropagation(); 160 | evt.preventDefault(); 161 | }} 162 | > 163 | {MediaLibComponent && mediaLibConfiguration.selected && ( 164 | 174 | )} 175 |
176 | 177 | ); 178 | }; 179 | 180 | Editor.propTypes = { 181 | onChange: PropTypes.func.isRequired, 182 | name: PropTypes.string.isRequired, 183 | value: PropTypes.object, 184 | }; 185 | 186 | export default Editor; 187 | -------------------------------------------------------------------------------- /admin/src/components/Wysiwyg/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; // eslint-disable-line import/no-unresolved 2 | import PropTypes from 'prop-types'; 3 | import { isEmpty } from 'lodash'; 4 | import { Label, InputDescription, InputErrors } from 'strapi-helper-plugin'; // eslint-disable-line import/no-unresolved 5 | import Editor from '../GrapesEditor'; 6 | 7 | const Wysiwyg = ({ inputDescription, errors, label, name, noErrorsDescription, onChange, value }) => { 8 | let spacer = !isEmpty(inputDescription) ?
:
; 9 | 10 | if (!noErrorsDescription && !isEmpty(errors)) { 11 | spacer =
; 12 | } 13 | 14 | return ( 15 |
22 |
29 | ); 30 | }; 31 | 32 | Wysiwyg.defaultProps = { 33 | errors: [], 34 | inputDescription: null, 35 | label: '', 36 | noErrorsDescription: false, 37 | value: '', 38 | }; 39 | 40 | Wysiwyg.propTypes = { 41 | errors: PropTypes.array, 42 | inputDescription: PropTypes.oneOfType([ 43 | PropTypes.string, 44 | PropTypes.func, 45 | PropTypes.shape({ 46 | id: PropTypes.string, 47 | params: PropTypes.object, 48 | }), 49 | ]), 50 | label: PropTypes.oneOfType([ 51 | PropTypes.string, 52 | PropTypes.func, 53 | PropTypes.shape({ 54 | id: PropTypes.string, 55 | params: PropTypes.object, 56 | }), 57 | ]), 58 | name: PropTypes.string.isRequired, 59 | noErrorsDescription: PropTypes.bool, 60 | onChange: PropTypes.func.isRequired, 61 | value: PropTypes.object, 62 | }; 63 | 64 | export default Wysiwyg; 65 | -------------------------------------------------------------------------------- /admin/src/containers/App/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * This component is the skeleton around the actual pages, and should only 4 | * contain code that should be seen on all pages. (e.g. navigation bar) 5 | * 6 | */ 7 | 8 | import React from 'react'; 9 | import { Switch, Route } from 'react-router-dom'; 10 | import { NotFound } from 'strapi-helper-plugin'; 11 | // Utils 12 | import pluginId from '../../pluginId'; 13 | // Containers 14 | import HomePage from '../HomePage'; 15 | 16 | const App = () => { 17 | return ( 18 |
19 | 20 | 21 | 22 | 23 |
24 | ); 25 | }; 26 | 27 | export default App; 28 | -------------------------------------------------------------------------------- /admin/src/containers/HomePage/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * HomePage 4 | * 5 | */ 6 | 7 | import React, { memo } from 'react'; 8 | // import PropTypes from 'prop-types'; 9 | import pluginId from '../../pluginId'; 10 | 11 | const HomePage = () => { 12 | return ( 13 |
14 |

{pluginId}'s HomePage

15 |

Happy coding

16 |
17 | ); 18 | }; 19 | 20 | export default memo(HomePage); 21 | -------------------------------------------------------------------------------- /admin/src/containers/Initializer/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Initializer 4 | * 5 | */ 6 | 7 | import { useEffect, useRef } from 'react'; 8 | import PropTypes from 'prop-types'; 9 | import pluginId from '../../pluginId'; 10 | 11 | const Initializer = ({ updatePlugin }) => { 12 | const ref = useRef(); 13 | ref.current = updatePlugin; 14 | 15 | useEffect(() => { 16 | ref.current(pluginId, 'isReady', true); 17 | }, []); 18 | 19 | return null; 20 | }; 21 | 22 | Initializer.propTypes = { 23 | updatePlugin: PropTypes.func.isRequired, 24 | }; 25 | 26 | export default Initializer; 27 | -------------------------------------------------------------------------------- /admin/src/containers/Settings/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; // eslint-disable-line import/no-unresolved 2 | import PropTypes from 'prop-types'; 3 | import { Switch, Route } from 'react-router-dom'; // eslint-disable-line import/no-unresolved 4 | import { Button } from '@buffetjs/core'; // eslint-disable-line import/no-unresolved 5 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; // eslint-disable-line import/no-unresolved 6 | import { faGithub } from '@fortawesome/free-brands-svg-icons'; // eslint-disable-line import/no-unresolved 7 | import pluginId from '../../pluginId'; 8 | import image from '../../../../admin/src/components/GrapesEditor/assets/img/demo.png'; 9 | 10 | const GeneralBlock = () => ( 11 |
12 |

General

13 |

This section has no content yet.

14 | 15 |
16 | ); 17 | const AboutBlock = () => ( 18 |
19 |

About

20 |

21 | This plugin is developped and maintained by{' '} 22 | 23 | Uwizy 24 | 25 | . 26 |

27 |
28 |

29 | 30 | 33 | 34 |

35 |
36 | ); 37 | 38 | const Settings = ({ settingsBaseURL }) => { 39 | return ( 40 | 41 | 42 | 43 | 44 | ); 45 | }; 46 | 47 | Settings.propTypes = { 48 | settingsBaseURL: PropTypes.string.isRequired, 49 | }; 50 | 51 | export default Settings; 52 | -------------------------------------------------------------------------------- /admin/src/index.js: -------------------------------------------------------------------------------- 1 | import pluginPkg from '../../package.json'; 2 | import Wysiwyg from './components/Wysiwyg'; 3 | import pluginId from './pluginId'; 4 | import Settings from './containers/Settings'; 5 | 6 | export default (strapi) => { 7 | const pluginDescription = pluginPkg.strapi.description || pluginPkg.description; 8 | const menuSection = { 9 | id: pluginId, 10 | title: { 11 | id: `${pluginId}.foo`, 12 | defaultMessage: 'Webpage Builder', 13 | }, 14 | links: [ 15 | { 16 | title: 'General', 17 | to: `${strapi.settingsBaseURL}/${pluginId}/general`, 18 | name: 'general', 19 | }, 20 | { 21 | title: { 22 | id: `${pluginId}.bar`, 23 | defaultMessage: 'About', 24 | }, 25 | to: `${strapi.settingsBaseURL}/${pluginId}/about`, 26 | name: 'about', 27 | }, 28 | ], 29 | }; 30 | 31 | const plugin = { 32 | blockerComponent: null, 33 | blockerComponentProps: {}, 34 | description: pluginDescription, 35 | icon: pluginPkg.strapi.icon, 36 | id: pluginId, 37 | initializer: () => null, 38 | injectedComponents: [], 39 | isReady: true, 40 | isRequired: pluginPkg.strapi.required || false, 41 | leftMenuLinks: [], 42 | leftMenuSections: [], 43 | mainComponent: null, 44 | name: pluginPkg.strapi.name, 45 | preventComponentRendering: false, 46 | settings: { 47 | mainComponent: Settings, 48 | menuSection, 49 | }, 50 | trads: {}, 51 | }; 52 | 53 | strapi.registerField({ type: 'json', Component: Wysiwyg }); 54 | 55 | return strapi.registerPlugin(plugin); 56 | }; 57 | -------------------------------------------------------------------------------- /admin/src/lifecycles.js: -------------------------------------------------------------------------------- 1 | function lifecycles() {} 2 | 3 | export default lifecycles; 4 | -------------------------------------------------------------------------------- /admin/src/pluginId.js: -------------------------------------------------------------------------------- 1 | const pluginPkg = require('../../package.json'); 2 | 3 | const pluginId = pluginPkg.name.replace(/^strapi-plugin-/i, ''); 4 | 5 | module.exports = pluginId; 6 | -------------------------------------------------------------------------------- /admin/src/translations/ar.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /admin/src/translations/cs.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /admin/src/translations/de.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /admin/src/translations/en.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /admin/src/translations/es.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /admin/src/translations/fr.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /admin/src/translations/index.js: -------------------------------------------------------------------------------- 1 | import ar from './ar.json'; 2 | import cs from './cs.json'; 3 | import de from './de.json'; 4 | import en from './en.json'; 5 | import es from './es.json'; 6 | import fr from './fr.json'; 7 | import it from './it.json'; 8 | import ko from './ko.json'; 9 | import nl from './nl.json'; 10 | import pl from './pl.json'; 11 | import ptBR from './pt-BR.json'; 12 | import pt from './pt.json'; 13 | import ru from './ru.json'; 14 | import tr from './tr.json'; 15 | import vi from './vi.json'; 16 | import zhHans from './zh-Hans.json'; 17 | import zh from './zh.json'; 18 | import sk from './sk.json'; 19 | 20 | const trads = { 21 | ar, 22 | cs, 23 | de, 24 | en, 25 | es, 26 | fr, 27 | it, 28 | ko, 29 | nl, 30 | pl, 31 | 'pt-BR': ptBR, 32 | pt, 33 | ru, 34 | tr, 35 | vi, 36 | 'zh-Hans': zhHans, 37 | zh, 38 | sk, 39 | }; 40 | 41 | export default trads; 42 | -------------------------------------------------------------------------------- /admin/src/translations/it.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /admin/src/translations/ko.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /admin/src/translations/nl.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /admin/src/translations/pl.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /admin/src/translations/pt-BR.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /admin/src/translations/pt.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /admin/src/translations/ru.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /admin/src/translations/sk.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /admin/src/translations/tr.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /admin/src/translations/vi.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /admin/src/translations/zh-Hans.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /admin/src/translations/zh.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /admin/src/utils/getTrad.js: -------------------------------------------------------------------------------- 1 | import pluginId from '../pluginId'; 2 | 3 | const getTrad = (id) => `${pluginId}.${id}`; 4 | 5 | export default getTrad; 6 | -------------------------------------------------------------------------------- /config/routes.json: -------------------------------------------------------------------------------- 1 | { 2 | "routes": [ 3 | 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /controllers/strapi-plugin-webpage-builder.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * test-plugin.js controller 5 | * 6 | * @description: A set of functions called "actions" of the `test-plugin` plugin. 7 | */ 8 | 9 | module.exports = { 10 | /** 11 | * Default action. 12 | * 13 | * @return {Object} 14 | */ 15 | 16 | index: async(ctx) => { 17 | // Add your own logic here. 18 | 19 | // Send 200 `ok` 20 | ctx.send({ 21 | message: 'ok', 22 | }); 23 | }, 24 | }; -------------------------------------------------------------------------------- /main.scss: -------------------------------------------------------------------------------- 1 | /* stylelint-disable */ 2 | 3 | @import "~spectrum-colorpicker/spectrum"; 4 | @import "~codemirror/lib/codemirror"; 5 | @import "~codemirror/theme/hopscotch"; 6 | @import "gjs_variables.scss"; 7 | @font-face { 8 | font-family: 'font3336'; 9 | src: url('#{$fontPath}/#{$fontName}.eot?v=#{$fontV}'); 10 | src : url('#{$fontPath}/#{$fontName}.woff?v=#{$fontV}') format('woff'), //url('#{$fontPath}/#{$fontName}.woff2?v=#{$fontV}') format('woff2'), 11 | url('#{$fontPath}/#{$fontName}.ttf?v=#{$fontV}') format('truetype'), 12 | url('#{$fontPath}/#{$fontName}.svg?v=#{$fontV}') format('svg'), 13 | url('#{$fontPath}/#{$fontName}.eot?v=#{$fontV}') format('embedded-opentype'); 14 | font-weight: normal; 15 | font-style: normal; 16 | } 17 | 18 | @mixin user-select($v) { 19 | -moz-user-select: $v; 20 | -khtml-user-select: $v; 21 | -webkit-user-select: $v; 22 | -ms-user-select: $v; 23 | -o-user-select: $v; 24 | user-select: $v; 25 | } 26 | 27 | @mixin opacity($v) { 28 | opacity: $v; 29 | filter: alpha(opacity=$v * 100); 30 | } 31 | 32 | @mixin appearance($v) { 33 | -webkit-appearance: $v; 34 | -moz-appearance: $v; 35 | appearance: $v; 36 | } 37 | 38 | @mixin transform($v) { 39 | -ms-transform: $v; 40 | -webkit-transform: $v; 41 | -moz-transform: $v; 42 | transform: $v; 43 | } 44 | 45 | $prefix: $app-prefix; 46 | @import "gjs_status"; 47 | $colorsAll: (one, 48 | $primaryColor), 49 | (two, 50 | $secondaryColor), 51 | (three, 52 | $tertiaryColor), 53 | (four, 54 | $quaternaryColor), 55 | (danger, 56 | $colorRed); 57 | .#{$prefix} { 58 | @each $cnum, 59 | $ccol in $colorsAll { 60 | &#{$cnum} { 61 | &-bg { 62 | background-color: $ccol; 63 | } 64 | &-color { 65 | color: $ccol; 66 | &-h:hover { 67 | color: $ccol; 68 | } 69 | } 70 | } 71 | } 72 | } 73 | 74 | .#{$app-prefix}bg { 75 | &-main { 76 | background-color: $mainColor; 77 | } 78 | } 79 | 80 | .#{$app-prefix}color { 81 | &-main { 82 | color: $fontColor; 83 | fill: $fontColor; 84 | } 85 | &-active { 86 | color: $fontColorActive; 87 | fill: $fontColorActive; 88 | } 89 | &-warn { 90 | color: $colorWarn; 91 | fill: $colorWarn; 92 | } 93 | &-hl { 94 | color: $colorHighlight; 95 | fill: $colorHighlight; 96 | } 97 | } 98 | 99 | .#{$app-prefix}fonts::before { 100 | display: block; 101 | font: normal normal normal 14px font3336; // shortening font declaration 102 | text-rendering: auto; // optimizelegibility throws things off #1094 103 | -webkit-font-smoothing: antialiased; 104 | -moz-osx-font-smoothing: grayscale; 105 | font-size: 5em; 106 | } 107 | 108 | .#{$app-prefix}f-b1::before { 109 | content: 'Q'; 110 | } 111 | 112 | .#{$app-prefix}f-b2::before { 113 | content: 'W'; 114 | } 115 | 116 | .#{$app-prefix}f-b3::before { 117 | content: 'E'; 118 | } 119 | 120 | .#{$app-prefix}f-b37::before { 121 | content: 'R'; 122 | } 123 | 124 | .#{$app-prefix}f-hero::before { 125 | content: 'T'; 126 | } 127 | 128 | .#{$app-prefix}f-h1p::before { 129 | content: 'y'; 130 | } 131 | 132 | .#{$app-prefix}f-3ba::before { 133 | content: 'u'; 134 | } 135 | 136 | .#{$app-prefix}f-image::before { 137 | content: 'I'; 138 | } 139 | 140 | .#{$app-prefix}f-text::before { 141 | content: 'o'; 142 | } 143 | 144 | .#{$app-prefix}f-quo::before { 145 | content: 'p'; 146 | } 147 | 148 | .#{$app-prefix}f-button::before { 149 | content: 'B'; 150 | } 151 | 152 | .#{$app-prefix}f-divider::before { 153 | content: 'D'; 154 | } 155 | 156 | .#{$app-prefix}invis-invis, 157 | .#{$app-prefix}no-app { 158 | background-color: transparent; 159 | border: none; 160 | color: inherit; 161 | } 162 | 163 | .#{$app-prefix}no-app { 164 | height: 10px; 165 | } 166 | 167 | .#{$app-prefix}test { 168 | &::btn { 169 | color: '#fff'; 170 | } 171 | &input {} 172 | &header {} 173 | } 174 | 175 | .opac50 { 176 | @include opacity(0.50); 177 | } 178 | 179 | .#{$app-prefix}checker-bg, 180 | .checker-bg { 181 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg=="); 182 | } 183 | 184 | .#{$app-prefix}no-user-select { 185 | @include user-select(none); 186 | } 187 | 188 | .#{$app-prefix}no-pointer-events { 189 | pointer-events: none; 190 | } 191 | 192 | .#{$app-prefix}bdrag { 193 | pointer-events: none !important; 194 | position: absolute !important; 195 | z-index: 10 !important; 196 | width: auto; 197 | } 198 | 199 | .#{$app-prefix}drag-helper { 200 | background-color: $colorBlue !important; 201 | pointer-events: none !important; 202 | position: absolute !important; 203 | z-index: 10 !important; 204 | transform: scale(0.3) !important; 205 | transform-origin: top left !important; 206 | -webkit-transform-origin: top left !important; 207 | margin: 15px !important; 208 | transition: none !important; 209 | outline: none !important; 210 | } 211 | 212 | .#{$app-prefix}grabbing, 213 | .#{$app-prefix}grabbing * { 214 | @extend .#{$app-prefix}no-user-select; 215 | cursor: grabbing !important; 216 | cursor: -webkit-grabbing !important; 217 | } 218 | 219 | .#{$app-prefix}grabbing { 220 | overflow: hidden; 221 | } 222 | 223 | .#{$app-prefix}off-prv { 224 | @extend .#{$app-prefix}color-main; 225 | @extend .#{$app-prefix}bg-main; 226 | position: relative; 227 | z-index: 10; 228 | padding: 5px; 229 | cursor: pointer; 230 | } 231 | 232 | // Custom scrollbars for Chrome 233 | .#{$app-prefix}editor-cont ::-webkit-scrollbar-track { 234 | background: $mainDklColor; 235 | } 236 | 237 | .#{$app-prefix}editor-cont ::-webkit-scrollbar-thumb { 238 | background-color: rgba(255, 255, 255, 0.2); 239 | } 240 | 241 | .#{$app-prefix}editor-cont ::-webkit-scrollbar { 242 | width: 8px; 243 | } 244 | 245 | 246 | /********************* MAIN ************************/ 247 | 248 | .clear { 249 | clear: both 250 | } 251 | 252 | .no-select { 253 | @include user-select(none); 254 | } 255 | 256 | .#{$app-prefix} { 257 | &no-touch-actions { 258 | touch-action: none; 259 | } 260 | &disabled { 261 | @include user-select(none); 262 | @include opacity(0.50); 263 | } 264 | &editor { 265 | font-family: $mainFont; 266 | font-size: $fontSizeS; 267 | position: relative; 268 | box-sizing: border-box; 269 | height: 100%; 270 | } 271 | } 272 | 273 | .#{$app-prefix}freezed, 274 | .#{$nv-prefix}freezed { 275 | @include opacity(0.50); 276 | pointer-events: none; 277 | } 278 | 279 | @import "gjs_traits"; 280 | @import "gjs_canvas"; 281 | 282 | /********* COMMANDS **********/ 283 | 284 | .no-dots, 285 | .ui-resizable-handle { 286 | border: none !important; 287 | margin: 0 !important; 288 | outline: none !important; 289 | } 290 | 291 | .#{$com-prefix}dashed * { 292 | outline: 1px dashed #888; 293 | outline-offset: -2px; 294 | box-sizing: border-box; 295 | } 296 | 297 | .#{$com-prefix}no-select, 298 | .#{$com-prefix}no-select img { 299 | @extend .no-select; 300 | } 301 | 302 | .#{$cv-prefix}canvas .#{$comp-prefix}selected { 303 | //TODO 304 | outline: 3px solid $colorBlue !important; 305 | } 306 | 307 | *.#{$com-prefix}hover, 308 | div.#{$com-prefix}hover { 309 | outline: 1px solid $colorBlue; 310 | } 311 | 312 | *.#{$com-prefix}hover-delete, 313 | div.#{$com-prefix}hover-delete { 314 | outline: 2px solid $colorRed; 315 | @include opacity(0.50); 316 | } 317 | 318 | *.#{$com-prefix}hover-move, 319 | div.#{$com-prefix}hover-move { 320 | outline: 3px solid $colorYell; 321 | } 322 | 323 | .#{$com-prefix}badge, 324 | .#{$app-prefix}badge { 325 | pointer-events: none; 326 | background-color: $colorBlue; 327 | color: #fff; 328 | padding: 2px 5px; 329 | position: absolute; 330 | z-index: 1; 331 | font-size: 12px; 332 | outline: none; 333 | display: none; 334 | } 335 | 336 | .#{$com-prefix}badge-red { 337 | @extend .#{$com-prefix}badge; 338 | background-color: $colorRed; 339 | } 340 | 341 | .#{$app-prefix}badge-warning { 342 | background-color: $colorYell; 343 | } 344 | 345 | .#{$app-prefix}placeholder, 346 | .#{$com-prefix}placeholder, 347 | .#{$nv-prefix}placeholder { 348 | position: absolute; 349 | z-index: 10; 350 | pointer-events: none; 351 | display: none; 352 | } 353 | 354 | .#{$app-prefix}placeholder, 355 | .#{$nv-prefix}placeholder { 356 | border-style: solid !important; 357 | outline: none; 358 | box-sizing: border-box; 359 | transition: top $animSpeed, left $animSpeed, width $animSpeed, height $animSpeed; 360 | } 361 | 362 | .#{$app-prefix}placeholder.horizontal, 363 | .#{$com-prefix}placeholder.horizontal, 364 | .#{$nv-prefix}placeholder.horizontal { 365 | border-color: transparent $placeholderColor; 366 | border-width: 3px 5px; 367 | margin: -3px 0 0; 368 | } 369 | 370 | .#{$app-prefix}placeholder.vertical, 371 | .#{$com-prefix}placeholder.vertical, 372 | .#{$nv-prefix}placeholder.vertical { 373 | border-color: $placeholderColor transparent; 374 | border-width: 5px 3px; 375 | margin: 0 0 0 -3px; 376 | } 377 | 378 | .#{$app-prefix}placeholder-int, 379 | .#{$com-prefix}placeholder-int, 380 | .#{$nv-prefix}placeholder-int { 381 | background-color: $placeholderColor; 382 | box-shadow: 0 0 3px rgba(0, 0, 0, 0.2); 383 | height: 100%; 384 | width: 100%; 385 | pointer-events: none; 386 | padding: 1.5px; 387 | outline: none; 388 | } 389 | 390 | @import 'gjs_panels'; 391 | 392 | /*********** Components *************/ 393 | 394 | .#{$comp-prefix}image-placeholder { 395 | display: block; 396 | background-color: #f5f5f5; 397 | color: $fontColorDk; 398 | height: $imageCompDim; 399 | width: $imageCompDim; 400 | line-height: $imageCompDim; 401 | outline: 3px solid $colorYell; 402 | outline-offset: -3px; 403 | text-align: center; 404 | font-size: $imageCompDim/3; 405 | cursor: pointer; 406 | &.fa-picture-o::after { 407 | content: "\f03e"; 408 | } 409 | } 410 | 411 | @import "gjs_inputs"; 412 | @import "gjs_devices"; 413 | 414 | /********* General **********/ 415 | 416 | .#{$app-prefix}category-open { 417 | border-bottom: 1px solid rgba(0, 0, 0, 0.25); 418 | } 419 | 420 | .#{$app-prefix}category-title { 421 | @extend .no-select; 422 | font-weight: lighter; 423 | background-color: $mainDklColor; 424 | letter-spacing: 1px; 425 | padding: 9px 10px 9px 20px; 426 | border-bottom: 1px solid rgba(0, 0, 0, 0.25); 427 | text-align: left; 428 | position: relative; 429 | cursor: pointer; 430 | } 431 | 432 | @import "gjs_style_manager"; 433 | @import "gjs_blocks"; 434 | @import "gjs_layers"; 435 | @import "gjs_selectors"; 436 | @import "gjs_modal"; 437 | @import "gjs_assets"; 438 | 439 | /********* File uploader **********/ 440 | 441 | .#{$am-prefix}file-uploader { 442 | width: 55%; 443 | float: left; 444 | >form { 445 | background-color: $mainDklColor; 446 | border: 2px dashed; 447 | border-radius: 3px; 448 | position: relative; 449 | text-align: center; 450 | margin-bottom: 15px; 451 | &.#{$am-prefix}hover { 452 | border: 2px solid $colorGreen; 453 | color: lighten($colorGreen, 5%); 454 | /*#7ee07e*/ 455 | } 456 | &.#{$am-prefix}disabled { 457 | border-color: red; 458 | } 459 | ##{$am-prefix}uploadFile { 460 | @include opacity(0); 461 | padding: $uploadPadding; 462 | width: 100%; 463 | box-sizing: border-box; 464 | } 465 | } 466 | ##{$am-prefix}title { 467 | position: absolute; 468 | padding: $uploadPadding; 469 | width: 100%; 470 | } 471 | } 472 | 473 | 474 | /********* Code Manager **********/ 475 | 476 | .#{$cm-prefix}editor-c { 477 | float: left; 478 | box-sizing: border-box; 479 | width: 50%; 480 | .CodeMirror { 481 | height: 450px; 482 | } 483 | } 484 | 485 | .#{$cm-prefix}editor { 486 | font-size: 12px; 487 | &##{$cm-prefix}htmlmixed { 488 | padding-right: 10px; 489 | border-right: 1px solid $mainDkColor; 490 | ##{$cm-prefix}title { 491 | color: #a97d44; 492 | } 493 | } 494 | &##{$cm-prefix}css { 495 | padding-left: 10px; 496 | ##{$cm-prefix}title { 497 | color: #ddca7e; 498 | } 499 | } 500 | ##{$cm-prefix}title { 501 | background-color: $mainDkColor; 502 | font-size: 12px; 503 | padding: 5px 10px 3px; 504 | text-align: right; 505 | } 506 | } 507 | 508 | 509 | /*************RTE****************/ 510 | 511 | @import 'gjs_rte'; 512 | 513 | /********* Spectrum **********/ 514 | 515 | .#{$app-prefix}editor-cont { 516 | .sp-hue, 517 | .sp-slider { 518 | cursor: row-resize; 519 | } 520 | .sp-color, 521 | .sp-dragger { 522 | cursor: crosshair; 523 | } 524 | .sp-alpha-inner, 525 | .sp-alpha-handle { 526 | cursor: col-resize; 527 | } 528 | .sp-hue { 529 | left: 90%; 530 | } 531 | .sp-color { 532 | right: 15%; 533 | } 534 | .sp-container { 535 | border: 1px solid $mainDkColor; 536 | box-shadow: 0 0 7px $mainDkColor; 537 | border-radius: 3px; 538 | } 539 | .sp-picker-container { 540 | border: none; 541 | } 542 | .colpick_dark .colpick_color { 543 | outline: 1px solid $mainDkColor; 544 | } 545 | .sp-cancel, 546 | .sp-cancel:hover { 547 | bottom: -8px; 548 | color: #777 !important; 549 | font-size: 25px; 550 | left: 0; 551 | position: absolute; 552 | text-decoration: none; 553 | } 554 | .sp-alpha-handle { 555 | background-color: #ccc; 556 | border: 1px solid #555; 557 | width: 4px; 558 | } 559 | .sp-color, 560 | .sp-hue { 561 | border: 1px solid #333333; 562 | } 563 | .sp-slider { 564 | background-color: #ccc; 565 | border: 1px solid #555; 566 | height: 3px; 567 | left: -4px; 568 | width: 22px; 569 | } 570 | .sp-dragger { 571 | background: transparent; 572 | box-shadow: 0 0 0 1px #111; 573 | } 574 | .sp-button-container { 575 | float: none; 576 | width: 100%; 577 | position: relative; 578 | text-align: right; 579 | } 580 | .sp-container button, 581 | .sp-container button:hover, 582 | .sp-container button:active { 583 | background: $mainDkColor; 584 | border-color: $mainDkColor; 585 | color: $fontColor; 586 | text-shadow: none; 587 | box-shadow: none; 588 | padding: 3px 5px; 589 | } 590 | .sp-palette-container { 591 | border: none; 592 | float: none; 593 | margin: 0; 594 | padding: 5px 10px 0; 595 | } 596 | .sp-palette .sp-thumb-el, 597 | .sp-palette .sp-thumb-el:hover { 598 | border: 1px solid rgba(0, 0, 0, 0.9); 599 | } 600 | .sp-palette .sp-thumb-el:hover, 601 | .sp-palette .sp-thumb-el.sp-thumb-active { 602 | border-color: rgba(0, 0, 0, 0.9); 603 | } 604 | } 605 | 606 | .#{$app-prefix}hidden { 607 | display: none; 608 | } 609 | 610 | @keyframes #{$app-prefix}slide-down { 611 | 0% { 612 | transform: translate(0, -3rem); 613 | opacity: 0; 614 | } 615 | 100% { 616 | transform: translate(0, 0); 617 | opacity: 1; 618 | } 619 | } 620 | 621 | @keyframes #{$app-prefix}slide-up { 622 | 0% { 623 | transform: translate(0, 0); 624 | opacity: 1; 625 | } 626 | 100% { 627 | transform: translate(0, -3rem); 628 | opacity: 0; 629 | } 630 | } 631 | 632 | .cm-s-hopscotch span.cm-error { 633 | color: #ffffff; 634 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "strapi-plugin-webpage-builder", 3 | "version": "1.0.0-alpha.0.2", 4 | "description": "Add GrapesJS builder to your own strapi application.", 5 | "strapi": { 6 | "name": "webpage-builder", 7 | "icon": "plug", 8 | "description": "Add GrapesJS builder to your own strapi application." 9 | }, 10 | "dependencies": { 11 | "grapesjs": "^0.16.17", 12 | "grapesjs-blocks-basic": "^0.1.8", 13 | "grapesjs-plugin-ckeditor": "0.0.9", 14 | "grapesjs-preset-webpage": "^0.1.11", 15 | "node-html-parser": "^1.1.16", 16 | "react-jsx-parser": "^1.21.0", 17 | "react-style-tag": "^2.0.1", 18 | "styled-components": "^4.4.0", 19 | "underscore": "^1.9.1", 20 | "xregexp": "^4.2.4" 21 | }, 22 | "devDependencies": { 23 | "eslint": "^6.8.0", 24 | "eslint-config-prettier": "^6.11.0", 25 | "eslint-config-standard": "^14.1.1", 26 | "eslint-config-standard-react": "^9.2.0", 27 | "eslint-plugin-import": "^2.20.2", 28 | "eslint-plugin-node": "^11.1.0", 29 | "eslint-plugin-prettier": "^3.1.3", 30 | "eslint-plugin-promise": "^4.2.1", 31 | "eslint-plugin-react": "^7.19.0", 32 | "eslint-plugin-standard": "^4.0.1", 33 | "eslint-standard": "^1.0.2", 34 | "prettier": "2.0.5" 35 | }, 36 | "author": { 37 | "name": "Hugues BUREAU", 38 | "email": "dev@uwizy.com", 39 | "url": "https://uwizy.com" 40 | }, 41 | "maintainers": [{ 42 | "name": "Hugues BUREAU", 43 | "email": "dev@uwizy.com", 44 | "url": "https://uwizy.com" 45 | }], 46 | "engines": { 47 | "node": ">=10.0.0", 48 | "npm": ">=6.0.0" 49 | }, 50 | "repository": { 51 | "type": "git", 52 | "url": "https://github.com/uwizy/strapi-plugin-webpage-builder" 53 | }, 54 | "license": "MIT" 55 | } -------------------------------------------------------------------------------- /services/strapi-plugin-webpage-builder.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; 2 | --------------------------------------------------------------------------------