├── .gitignore
├── LICENSE
├── README.md
├── index.html
├── package-lock.json
├── package.json
├── src
├── blocks.ts
└── index.ts
├── tsconfig.json
└── webpack.config.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .settings/
3 | .sass-cache/
4 | .project
5 | .eslintrc
6 | .idea
7 | .npmrc
8 | npm-debug.log
9 | _index.html
10 |
11 | dist/
12 | img/
13 | images/
14 | private/
15 | docs/
16 | vendor/
17 | coverage/
18 | node_modules/
19 | bower_components/
20 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2017-current, Artur Arseniev
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without modification,
5 | are permitted provided that the following conditions are met:
6 |
7 | - Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 | - Redistributions in binary form must reproduce the above copyright notice, this
10 | list of conditions and the following disclaimer in the documentation and/or
11 | other materials provided with the distribution.
12 | - Neither the name "GrapesJS" nor the names of its contributors may be
13 | used to endorse or promote products derived from this software without
14 | specific prior written permission.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
23 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GrapesJS Basic Blocks
2 |
3 | This plugin contains some basic blocks for the GrapesJS editor
4 |
5 | [Demo](http://grapesjs.com/demo.html)
6 |
7 |
8 | ## Summary
9 |
10 | - Plugin name: `gjs-blocks-basic`
11 | - Blocks: `column1`, `column2`, `column3`, `column3-7`, `text`, `link`, `image`, `video`, `map`
12 |
13 | ## Options
14 |
15 | | Option | Description | Default |
16 | | --------------- | -------------------------------- | ----------------------------------------------------------------------------------------------- |
17 | | `blocks` | Which blocks to add | `['column1', 'column2', 'column3', 'column3-7', 'text', 'link', 'image', 'video', 'map']` (all) |
18 | | `category` | Category name | `Basic` |
19 | | `flexGrid` | Make use of flexbox for the grid | `false` |
20 | | `stylePrefix` | Classes prefix | `gjs-` |
21 | | `addBasicStyle` | Use basic CSS for blocks | `true` |
22 | | `labelColumn1` | 1 Column label | `1 Column` |
23 | | `labelColumn2` | 2 Columns label | `2 Columns` |
24 | | `labelColumn3` | 3 Columns label | `3 Columns` |
25 | | `labelColumn37` | 3/7 Columns label | `2 Columns 3/7` |
26 | | `labelText` | Text label | `Text` |
27 | | `labelLink` | Link label | `Link` |
28 | | `labelImage` | Image label | `Image` |
29 | | `labelVideo` | Video label | `Video` |
30 | | `labelMap` | Map label | `Map` |
31 | | `rowHeight` | Initial height | `75` |
32 |
33 | ## Download
34 |
35 | * CDN
36 | * `https://unpkg.com/grapesjs-blocks-basic`
37 | * NPM
38 | * `npm i grapesjs-blocks-basic`
39 | * GIT
40 | * `git clone https://github.com/GrapesJS/blocks-basic.git`
41 |
42 | ## Usage
43 |
44 | Directly in the browser
45 | ```html
46 |
47 |
48 |
49 |
50 |
51 |
52 |
64 | ```
65 |
66 | Modern javascript
67 | ```js
68 | import grapesjs from 'grapesjs';
69 | import plugin from 'grapesjs-blocks-basic';
70 |
71 | const editor = grapesjs.init({
72 | container : '#gjs',
73 | // ...
74 | plugins: [plugin],
75 | pluginsOpts: {
76 | [plugin]: { /* options */ }
77 | }
78 | // or
79 | plugins: [
80 | editor => plugin(editor, { /* options */ }),
81 | ],
82 | });
83 | ```
84 |
85 | ## Development
86 |
87 | Clone the repository
88 |
89 | ```sh
90 | $ git clone https://github.com/GrapesJS/blocks-basic.git
91 | $ cd grapesjs-blocks-basic
92 | ```
93 |
94 | Install it
95 |
96 | ```sh
97 | $ npm i
98 | ```
99 |
100 | Start the dev server
101 |
102 | ```sh
103 | $ npm start
104 | ```
105 |
106 | Build before the commit. This will also increase the patch level version of the package
107 |
108 | ```sh
109 | $ npm run build
110 | ```
111 |
112 |
113 | ## License
114 |
115 | BSD 3-Clause
116 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | GrapesJS Plugin
6 |
7 |
8 |
14 |
15 |
16 |
17 |
18 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "grapesjs-blocks-basic",
3 | "version": "1.0.2",
4 | "description": "Basic blocks for the GrapesJS editor",
5 | "main": "dist/index.js",
6 | "files": [
7 | "dist/"
8 | ],
9 | "scripts": {
10 | "build": "grapesjs-cli build",
11 | "start": "grapesjs-cli serve"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "https://github.com/GrapesJS/blocks-basic.git"
16 | },
17 | "keywords": [
18 | "grapesjs",
19 | "plugin",
20 | "blocks",
21 | "basic"
22 | ],
23 | "author": "Artur Arseniev",
24 | "license": "BSD-3-Clause",
25 | "devDependencies": {
26 | "grapesjs": "^0.21.2",
27 | "grapesjs-cli": "^4.1.1"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/blocks.ts:
--------------------------------------------------------------------------------
1 | import type { Editor, BlockProperties } from 'grapesjs';
2 | import { PluginOptions } from '.';
3 |
4 | export default function(editor: Editor, opts: Required) {
5 | const bm = editor.BlockManager;
6 | const { category, blocks, stylePrefix, flexGrid, rowHeight, addBasicStyle } = opts;
7 | const clsRow = `${stylePrefix}row`;
8 | const clsCell = `${stylePrefix}cell`;
9 | const styleRow = flexGrid
10 | ? `
11 | .${clsRow} {
12 | display: flex;
13 | justify-content: flex-start;
14 | align-items: stretch;
15 | flex-wrap: nowrap;
16 | padding: 10px;
17 | }
18 | @media (max-width: 768px) {
19 | .${clsRow} {
20 | flex-wrap: wrap;
21 | }
22 | }`
23 | : `
24 | .${clsRow} {
25 | display: table;
26 | padding: 10px;
27 | width: 100%;
28 | }
29 | @media (max-width: 768px) {
30 | .${stylePrefix}cell, .${stylePrefix}cell30, .${stylePrefix}cell70 {
31 | width: 100%;
32 | display: block;
33 | }
34 | }`;
35 | const styleClm = flexGrid
36 | ? `
37 | .${clsCell} {
38 | min-height: ${rowHeight}px;
39 | flex-grow: 1;
40 | flex-basis: 100%;
41 | }`
42 | : `
43 | .${clsCell} {
44 | width: 8%;
45 | display: table-cell;
46 | height: ${rowHeight}px;
47 | }`;
48 | const styleClm30 = `
49 | .${stylePrefix}cell30 {
50 | width: 30%;
51 | }`;
52 | const styleClm70 = `
53 | .${stylePrefix}cell70 {
54 | width: 70%;
55 | }`;
56 |
57 | const step = 0.2;
58 | const minDim = 1;
59 | const currentUnit = 1;
60 | const resizerBtm: Record = {
61 | tl: 0,
62 | tc: 0,
63 | tr: 0,
64 | cl: 0,
65 | cr: 0,
66 | bl: 0,
67 | br: 0,
68 | minDim
69 | };
70 | const resizerRight: Record = {
71 | ...resizerBtm,
72 | cr: 1,
73 | bc: 0,
74 | currentUnit,
75 | minDim,
76 | step
77 | };
78 |
79 | // Flex elements do not react on width style change therefore I use
80 | // 'flex-basis' as keyWidth for the resizer on columns
81 | if (flexGrid) {
82 | resizerRight.keyWidth = 'flex-basis';
83 | }
84 |
85 | const rowAttr = {
86 | class: clsRow,
87 | 'data-gjs-droppable': `.${clsCell}`,
88 | 'data-gjs-resizable': resizerBtm,
89 | 'data-gjs-name': 'Row'
90 | };
91 |
92 | const colAttr: Record = {
93 | class: clsCell,
94 | 'data-gjs-draggable': `.${clsRow}`,
95 | 'data-gjs-resizable': resizerRight,
96 | 'data-gjs-name': 'Cell'
97 | };
98 |
99 | if (flexGrid) {
100 | colAttr['data-gjs-unstylable'] = ['width'];
101 | colAttr['data-gjs-stylable-require'] = ['flex-basis'];
102 | }
103 |
104 | // Make row and column classes private
105 | const privateCls = [`.${clsRow}`, `.${clsCell}`];
106 | editor.on(
107 | 'selector:add',
108 | selector =>
109 | privateCls.indexOf(selector.getFullName()) >= 0 &&
110 | selector.set('private', 1)
111 | );
112 |
113 | const attrsToString = (attrs: Record) => {
114 | const result = [];
115 |
116 | for (let key in attrs) {
117 | let value = attrs[key];
118 | const toParse = value instanceof Array || value instanceof Object;
119 | value = toParse ? JSON.stringify(value) : value;
120 | result.push(`${key}=${toParse ? `'${value}'` : `'${value}'`}`);
121 | }
122 |
123 | return result.length ? ` ${result.join(' ')}` : '';
124 | };
125 |
126 | const toAdd = (name: string) => blocks.indexOf(name) >= 0;
127 | const attrsRow = attrsToString(rowAttr);
128 | const attrsCell = attrsToString(colAttr);
129 | const commonBlockProps: Partial = {
130 | category,
131 | select: true,
132 | };
133 |
134 | toAdd('column1') &&
135 | bm.add('column1', {
136 | ...commonBlockProps,
137 | label: opts.labelColumn1,
138 | media: ``,
141 | content: `
144 | ${
145 | addBasicStyle
146 | ? ``
150 | : ''
151 | }`
152 | });
153 |
154 | toAdd('column2') &&
155 | bm.add('column2', {
156 | ...commonBlockProps,
157 | label: opts.labelColumn2,
158 | media: ``,
161 | content: `
165 | ${
166 | addBasicStyle
167 | ? ``
171 | : ''
172 | }`
173 | });
174 |
175 | toAdd('column3') &&
176 | bm.add('column3', {
177 | ...commonBlockProps,
178 | label: opts.labelColumn3,
179 | media: ``,
182 | content: `
187 | ${
188 | addBasicStyle
189 | ? ``
193 | : ''
194 | }`
195 | });
196 |
197 | toAdd('column3-7') &&
198 | bm.add('column3-7', {
199 | ...commonBlockProps,
200 | label: opts.labelColumn37,
201 | media: ``,
204 | content: `
212 | ${
213 | addBasicStyle
214 | ? ``
220 | : ''
221 | }`
222 | });
223 |
224 | toAdd('text') &&
225 | bm.add('text', {
226 | ...commonBlockProps,
227 | activate: true,
228 | label: opts.labelText,
229 | media: ``,
232 | content: {
233 | type: 'text',
234 | content: 'Insert your text here',
235 | style: { padding: '10px' },
236 | }
237 | });
238 |
239 | toAdd('link') &&
240 | bm.add('link', {
241 | ...commonBlockProps,
242 | label: opts.labelLink,
243 | media: ``,
246 | content: {
247 | type: 'link',
248 | content: 'Link',
249 | style: { color: '#d983a6' }
250 | }
251 | });
252 |
253 | toAdd('image') &&
254 | bm.add('image', {
255 | ...commonBlockProps,
256 | activate: true,
257 | label: opts.labelImage,
258 | media: ``,
261 | content: {
262 | style: { color: 'black' },
263 | type: 'image',
264 | }
265 | });
266 |
267 | toAdd('video') &&
268 | bm.add('video', {
269 | ...commonBlockProps,
270 | label: opts.labelVideo,
271 | media: ``,
274 | content: {
275 | type: 'video',
276 | src: 'img/video2.webm',
277 | style: {
278 | height: '350px',
279 | width: '615px'
280 | }
281 | }
282 | });
283 |
284 | toAdd('map') &&
285 | bm.add('map', {
286 | ...commonBlockProps,
287 | label: opts.labelMap,
288 | media: ``,
291 | content: {
292 | type: 'map',
293 | style: { height: '350px' }
294 | }
295 | });
296 | }
297 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import type { Plugin } from 'grapesjs';
2 | import loadBlocks from './blocks';
3 |
4 | export type PluginOptions = {
5 | /**
6 | * Which blocks to add.
7 | * @default ['column1', 'column2', 'column3', 'column3-7', 'text', 'link', 'image', 'video', 'map']
8 | */
9 | blocks?: string[];
10 |
11 | /**
12 | * Make use of flexbox for the grid
13 | * @default false
14 | */
15 | flexGrid?: boolean;
16 |
17 | /**
18 | * Classes prefix
19 | * @default 'gjs-'
20 | */
21 | stylePrefix?: string;
22 |
23 | /**
24 | * Use basic CSS for blocks
25 | * @default true
26 | */
27 | addBasicStyle?: boolean;
28 |
29 | /**
30 | * Blocks category name
31 | * @default 'Basic'
32 | */
33 | category?: string;
34 |
35 | /**
36 | * 1 Column label
37 | * @default '1 Column'
38 | */
39 | labelColumn1?: string;
40 |
41 | /**
42 | * 2 Columns label
43 | * @default '2 Columns'
44 | */
45 | labelColumn2?: string;
46 |
47 | /**
48 | * 3 Columns label
49 | * @default '3 Columns'
50 | */
51 | labelColumn3?: string;
52 |
53 | /**
54 | * 3/7 Columns label
55 | * @default '2 Columns 3/7'
56 | */
57 | labelColumn37?: string;
58 |
59 | /**
60 | * Text label
61 | * @default 'Text'
62 | */
63 | labelText?: string;
64 |
65 | /**
66 | * Link label
67 | * @default 'Link'
68 | */
69 | labelLink?: string;
70 |
71 | /**
72 | * Image label
73 | * @default 'Image'
74 | */
75 | labelImage?: string;
76 |
77 | /**
78 | * Video label
79 | * @default 'Video'
80 | */
81 | labelVideo?: string;
82 |
83 | /**
84 | * Map label
85 | * @default 'Map'
86 | */
87 | labelMap?: string;
88 |
89 | /**
90 | * Initial row height
91 | * @default 75
92 | */
93 | rowHeight?: number;
94 | };
95 |
96 | const plugin: Plugin = (editor, opts = {}) => {
97 | const config: Required = {
98 | blocks: [
99 | 'column1',
100 | 'column2',
101 | 'column3',
102 | 'column3-7',
103 | 'text',
104 | 'link',
105 | 'image',
106 | 'video',
107 | 'map'
108 | ],
109 | flexGrid: false,
110 | stylePrefix: 'gjs-',
111 | addBasicStyle: true,
112 | category: 'Basic',
113 | labelColumn1: '1 Column',
114 | labelColumn2: '2 Columns',
115 | labelColumn3: '3 Columns',
116 | labelColumn37: '2 Columns 3/7',
117 | labelText: 'Text',
118 | labelLink: 'Link',
119 | labelImage: 'Image',
120 | labelVideo: 'Video',
121 | labelMap: 'Map',
122 | rowHeight: 75,
123 | ...opts
124 | };
125 |
126 | loadBlocks(editor, config);
127 | };
128 |
129 | export default plugin;
130 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./node_modules/grapesjs-cli/dist/template/tsconfig.json",
3 | "include": ["src"]
4 | }
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | module.exports = ({ config }) => ({
2 | ...config,
3 | output: {
4 | ...config.output,
5 | library: 'gjs-blocks-basic',
6 | },
7 | });
--------------------------------------------------------------------------------