More elements for mosaico mjml support. Added "MJML Sample" wizard to mosaico templates.
This commit is contained in:
parent
ec0f288d81
commit
94a2cdf89e
7 changed files with 415 additions and 12 deletions
|
@ -27,7 +27,7 @@ import {
|
||||||
} from '../../lib/namespace';
|
} from '../../lib/namespace';
|
||||||
import {DeleteModalDialog} from "../../lib/modals";
|
import {DeleteModalDialog} from "../../lib/modals";
|
||||||
|
|
||||||
import {getVersafix} from "../../../../shared/mosaico-templates";
|
import {getVersafix, getMJMLSample} from "../../../../shared/mosaico-templates";
|
||||||
import {
|
import {
|
||||||
getTemplateTypes,
|
getTemplateTypes,
|
||||||
getTemplateTypesOrder
|
getTemplateTypesOrder
|
||||||
|
@ -87,6 +87,15 @@ export default class CUD extends Component {
|
||||||
html: getVersafix()
|
html: getVersafix()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
} else if (wizard === 'mjml-sample') {
|
||||||
|
this.populateFormValues({
|
||||||
|
name: '',
|
||||||
|
description: '',
|
||||||
|
namespace: mailtrainConfig.user.namespace,
|
||||||
|
type: 'mjml',
|
||||||
|
mjml: getMJMLSample()
|
||||||
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
this.populateFormValues({
|
this.populateFormValues({
|
||||||
name: '',
|
name: '',
|
||||||
|
@ -183,7 +192,7 @@ export default class CUD extends Component {
|
||||||
<Form stateOwner={this} onSubmitAsync={::this.submitHandler}>
|
<Form stateOwner={this} onSubmitAsync={::this.submitHandler}>
|
||||||
<InputField id="name" label={t('name')}/>
|
<InputField id="name" label={t('name')}/>
|
||||||
<TextArea id="description" label={t('description')}/>
|
<TextArea id="description" label={t('description')}/>
|
||||||
{isEdit ?
|
{isEdit || this.props.wizard ?
|
||||||
<StaticField id="type" className={styles.formDisabled} label={t('type')}>
|
<StaticField id="type" className={styles.formDisabled} label={t('type')}>
|
||||||
{typeKey && this.templateTypes[typeKey].typeName}
|
{typeKey && this.templateTypes[typeKey].typeName}
|
||||||
</StaticField>
|
</StaticField>
|
||||||
|
|
|
@ -123,6 +123,7 @@ export default class List extends Component {
|
||||||
<ButtonDropdown buttonClassName="btn-primary" menuClassName="dropdown-menu-right" label={t('createMosaicoTemplate')}>
|
<ButtonDropdown buttonClassName="btn-primary" menuClassName="dropdown-menu-right" label={t('createMosaicoTemplate')}>
|
||||||
<DropdownLink to="/templates/mosaico/create">{t('blank')}</DropdownLink>
|
<DropdownLink to="/templates/mosaico/create">{t('blank')}</DropdownLink>
|
||||||
<DropdownLink to="/templates/mosaico/create/versafix">{t('versafixOne')}</DropdownLink>
|
<DropdownLink to="/templates/mosaico/create/versafix">{t('versafixOne')}</DropdownLink>
|
||||||
|
<DropdownLink to="/templates/mosaico/create/mjml-sample">{t('MJML Sample')}</DropdownLink>
|
||||||
</ButtonDropdown>
|
</ButtonDropdown>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@ export function getTemplateTypes(t) {
|
||||||
owner.setFormStatusMessage('success', t('MJML is valid.'));
|
owner.setFormStatusMessage('success', t('MJML is valid.'));
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
owner.setFormStatusMessage('danger', t('Invalid MJML.'));
|
owner.setFormStatusMessage('danger', t('Invalid MJML.'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ function handleMosaicoEditable(block, src) {
|
||||||
|
|
||||||
|
|
||||||
for (const attrMatch of attrsMatches) {
|
for (const attrMatch of attrsMatches) {
|
||||||
if (attrMatch[1] === 'mosaico-editable') {
|
if (attrMatch[1] === 'mj-mosaico-editable') {
|
||||||
const propertyId = attrMatch[2];
|
const propertyId = attrMatch[2];
|
||||||
block.addMosaicoProperty(propertyId);
|
block.addMosaicoProperty(propertyId);
|
||||||
|
|
||||||
|
@ -80,13 +80,24 @@ class MjMosaicoProperty extends HeadComponent {
|
||||||
static allowedAttributes = {
|
static allowedAttributes = {
|
||||||
'property-id': 'string',
|
'property-id': 'string',
|
||||||
label: 'string',
|
label: 'string',
|
||||||
widget: 'string',
|
type: 'enum(image,link)'
|
||||||
}
|
}
|
||||||
|
|
||||||
handler() {
|
handler() {
|
||||||
const { add } = this.context;
|
const { add } = this.context;
|
||||||
|
|
||||||
add('style', ` @supports -ko-blockdefs { ${this.getAttribute('property-id')} { label: ${this.getAttribute('label')}; widget: ${this.getAttribute('widget')} } }`);
|
let properties = null;
|
||||||
|
|
||||||
|
const type = this.getAttribute('type');
|
||||||
|
if (type === 'image') {
|
||||||
|
properties = 'src url alt';
|
||||||
|
} else if (type === 'link') {
|
||||||
|
properties = 'text url';
|
||||||
|
}
|
||||||
|
|
||||||
|
const propertiesStr = properties ? ` properties: ${properties}` : '';
|
||||||
|
|
||||||
|
add('style', ` @supports -ko-blockdefs { ${this.getAttribute('property-id')} { label: ${this.getAttribute('label')};${propertiesStr} } }`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,7 +258,10 @@ class MjMosaicoImage extends BodyComponent {
|
||||||
const propertyId = this.getAttribute('property-id');
|
const propertyId = this.getAttribute('property-id');
|
||||||
this.propertyId = propertyId || `image_${getId()}`;
|
this.propertyId = propertyId || `image_${getId()}`;
|
||||||
|
|
||||||
getParent().addMosaicoProperty(this.propertyId);
|
const parentBlock = getParent();
|
||||||
|
if (parentBlock) {
|
||||||
|
parentBlock.addMosaicoProperty(this.propertyId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static tagOmission = true
|
static tagOmission = true
|
||||||
|
@ -425,6 +439,154 @@ class MjMosaicoImage extends BodyComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Adapted from https://github.com/mjmlio/mjml/blob/master/packages/mjml-button/src/index.js
|
||||||
|
class MjMosaicoButton extends BodyComponent {
|
||||||
|
constructor(initialDatas = {}) {
|
||||||
|
super(initialDatas);
|
||||||
|
|
||||||
|
const propertyId = this.getAttribute('property-id');
|
||||||
|
this.propertyId = propertyId || `button_${getId()}`;
|
||||||
|
|
||||||
|
const parentBlock = getParent();
|
||||||
|
if (parentBlock) {
|
||||||
|
parentBlock.addMosaicoProperty(this.propertyId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static endingTag = true
|
||||||
|
|
||||||
|
static allowedAttributes = {
|
||||||
|
'property-id': 'string',
|
||||||
|
align: 'enum(left,center,right)',
|
||||||
|
'background-color': 'color',
|
||||||
|
'border-bottom': 'string',
|
||||||
|
'border-left': 'string',
|
||||||
|
'border-radius': 'string',
|
||||||
|
'border-right': 'string',
|
||||||
|
'border-top': 'string',
|
||||||
|
border: 'string',
|
||||||
|
color: 'color',
|
||||||
|
'container-background-color': 'color',
|
||||||
|
'font-family': 'string',
|
||||||
|
'font-size': 'unit(px)',
|
||||||
|
'font-style': 'string',
|
||||||
|
'font-weight': 'string',
|
||||||
|
height: 'unit(px,%)',
|
||||||
|
name: 'string',
|
||||||
|
'inner-padding': 'unit(px,%)',
|
||||||
|
'line-height': 'unit(px,%)',
|
||||||
|
'padding-bottom': 'unit(px,%)',
|
||||||
|
'padding-left': 'unit(px,%)',
|
||||||
|
'padding-right': 'unit(px,%)',
|
||||||
|
'padding-top': 'unit(px,%)',
|
||||||
|
padding: 'unit(px,%){1,4}',
|
||||||
|
rel: 'string',
|
||||||
|
target: 'string',
|
||||||
|
'text-decoration': 'string',
|
||||||
|
'text-transform': 'string',
|
||||||
|
'vertical-align': 'enum(top,bottom,middle)',
|
||||||
|
'text-align': 'enum(left,right,center)',
|
||||||
|
width: 'unit(px,%)',
|
||||||
|
}
|
||||||
|
|
||||||
|
static defaultAttributes = {
|
||||||
|
align: 'center',
|
||||||
|
'background-color': '#414141',
|
||||||
|
border: 'none',
|
||||||
|
'border-radius': '3px',
|
||||||
|
color: '#ffffff',
|
||||||
|
'font-family': 'Ubuntu, Helvetica, Arial, sans-serif',
|
||||||
|
'font-size': '13px',
|
||||||
|
'font-weight': 'normal',
|
||||||
|
'inner-padding': '10px 25px',
|
||||||
|
'line-height': '120%',
|
||||||
|
padding: '10px 25px',
|
||||||
|
target: '_blank',
|
||||||
|
'text-decoration': 'none',
|
||||||
|
'text-transform': 'none',
|
||||||
|
'vertical-align': 'middle',
|
||||||
|
}
|
||||||
|
|
||||||
|
getStyles() {
|
||||||
|
return {
|
||||||
|
table: {
|
||||||
|
'border-collapse': 'separate',
|
||||||
|
width: this.getAttribute('width'),
|
||||||
|
'line-height': '100%',
|
||||||
|
},
|
||||||
|
td: {
|
||||||
|
border: this.getAttribute('border'),
|
||||||
|
'border-bottom': this.getAttribute('border-bottom'),
|
||||||
|
'border-left': this.getAttribute('border-left'),
|
||||||
|
'border-radius': this.getAttribute('border-radius'),
|
||||||
|
'border-right': this.getAttribute('border-right'),
|
||||||
|
'border-top': this.getAttribute('border-top'),
|
||||||
|
cursor: 'auto',
|
||||||
|
'font-style': this.getAttribute('font-style'),
|
||||||
|
height: this.getAttribute('height'),
|
||||||
|
padding: this.getAttribute('inner-padding'),
|
||||||
|
'text-align': this.getAttribute('text-align'),
|
||||||
|
background: this.getAttribute('background-color'),
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
background: this.getAttribute('background-color'),
|
||||||
|
color: this.getAttribute('color'),
|
||||||
|
'font-family': this.getAttribute('font-family'),
|
||||||
|
'font-size': this.getAttribute('font-size'),
|
||||||
|
'font-style': this.getAttribute('font-style'),
|
||||||
|
'font-weight': this.getAttribute('font-weight'),
|
||||||
|
'line-height': this.getAttribute('line-height'),
|
||||||
|
Margin: '0',
|
||||||
|
'text-decoration': this.getAttribute('text-decoration'),
|
||||||
|
'text-transform': this.getAttribute('text-transform'),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return `
|
||||||
|
<table
|
||||||
|
${this.htmlAttributes({
|
||||||
|
border: '0',
|
||||||
|
cellpadding: '0',
|
||||||
|
cellspacing: '0',
|
||||||
|
role: 'presentation',
|
||||||
|
style: 'table',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<tr>
|
||||||
|
<td
|
||||||
|
${this.htmlAttributes({
|
||||||
|
align: 'center',
|
||||||
|
bgcolor:
|
||||||
|
this.getAttribute('background-color') === 'none'
|
||||||
|
? undefined
|
||||||
|
: this.getAttribute('background-color'),
|
||||||
|
role: 'presentation',
|
||||||
|
style: 'td',
|
||||||
|
valign: this.getAttribute('vertical-align'),
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
${this.htmlAttributes({
|
||||||
|
rel: this.getAttribute('rel'),
|
||||||
|
name: this.getAttribute('name'),
|
||||||
|
style: 'content',
|
||||||
|
target: this.getAttribute('target'),
|
||||||
|
'data-ko-editable': this.getAttribute('property-id') + '.text',
|
||||||
|
'data-ko-link': this.getAttribute('property-id') + '.url'
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
${this.getContent()}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const mjmlInstance = new MJML();
|
const mjmlInstance = new MJML();
|
||||||
|
|
||||||
|
@ -432,15 +594,21 @@ mjmlInstance.registerComponent(MjMosaicoContainer);
|
||||||
mjmlInstance.registerComponent(MjMosaicoBlock);
|
mjmlInstance.registerComponent(MjMosaicoBlock);
|
||||||
mjmlInstance.registerComponent(MjMosaicoInnerBlock);
|
mjmlInstance.registerComponent(MjMosaicoInnerBlock);
|
||||||
mjmlInstance.registerComponent(MjMosaicoImage);
|
mjmlInstance.registerComponent(MjMosaicoImage);
|
||||||
|
mjmlInstance.registerComponent(MjMosaicoButton);
|
||||||
mjmlInstance.registerComponent(MjMosaicoProperty);
|
mjmlInstance.registerComponent(MjMosaicoProperty);
|
||||||
|
|
||||||
mjmlInstance.registerDependencies({
|
mjmlInstance.registerDependencies({
|
||||||
'mj-mosaico-container': ['mj-mosaico-block', 'mj-mosaico-inner-block'],
|
'mj-mosaico-container': ['mj-mosaico-block', 'mj-mosaico-inner-block'],
|
||||||
'mj-body': ['mj-mosaico-container', 'mj-mosaico-block'],
|
'mj-body': ['mj-mosaico-container', 'mj-mosaico-block'],
|
||||||
'mj-section': ['mj-mosaico-container', 'mj-mosaico-block'],
|
'mj-section': ['mj-mosaico-container', 'mj-mosaico-block'],
|
||||||
'mj-column': ['mj-mosaico-container', 'mj-mosaico-inner-block', 'mj-mosaico-image'],
|
'mj-column': ['mj-mosaico-container', 'mj-mosaico-inner-block', 'mj-mosaico-image', 'mj-mosaico-button'],
|
||||||
'mj-mosaico-block': ['mj-section', 'mj-column'],
|
'mj-mosaico-block': ['mj-section', 'mj-column'],
|
||||||
'mj-mosaico-inner-block': ['mj-mosaico-image', 'mj-divider', 'mj-text', 'mj-image', 'mj-table']
|
'mj-mosaico-inner-block': [
|
||||||
|
'mj-mosaico-image', 'mj-mosaico-button',
|
||||||
|
'mj-accordion', 'mj-button', 'mj-carousel', 'mj-divider', 'mj-html', 'mj-image', 'mj-invoice', 'mj-list',
|
||||||
|
'mj-location', 'mj-raw', 'mj-social', 'mj-spacer', 'mj-table', 'mj-text', 'mj-navbar'
|
||||||
|
],
|
||||||
|
'mj-head': ['mj-mosaico-property']
|
||||||
});
|
});
|
||||||
|
|
||||||
mjmlInstance.addToHeader(`
|
mjmlInstance.addToHeader(`
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
"bluebird": "^3.5.3",
|
"bluebird": "^3.5.3",
|
||||||
"body-parser": "^1.18.3",
|
"body-parser": "^1.18.3",
|
||||||
"bounce-handler": "7.3.2-fork.3",
|
"bounce-handler": "7.3.2-fork.3",
|
||||||
|
"capitalize": "^2.0.0",
|
||||||
"compression": "^1.7.3",
|
"compression": "^1.7.3",
|
||||||
"config": "^3.0.1",
|
"config": "^3.0.1",
|
||||||
"connect-flash": "^0.1.1",
|
"connect-flash": "^0.1.1",
|
||||||
|
|
|
@ -10,6 +10,7 @@ const gm = require('gm').subClass({
|
||||||
imageMagick: true
|
imageMagick: true
|
||||||
});
|
});
|
||||||
const users = require('../models/users');
|
const users = require('../models/users');
|
||||||
|
const capitalize = require('capitalize');
|
||||||
|
|
||||||
const fs = require('fs-extra')
|
const fs = require('fs-extra')
|
||||||
|
|
||||||
|
@ -51,7 +52,7 @@ users.registerRestrictedAccessTokenMethod('mosaico', async ({entityTypeId, entit
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
async function placeholderImage(width, height) {
|
async function placeholderImage(width, height, labelText, labelColor) {
|
||||||
const magick = gm(width, height, '#707070');
|
const magick = gm(width, height, '#707070');
|
||||||
const streamAsync = bluebird.promisify(magick.stream.bind(magick));
|
const streamAsync = bluebird.promisify(magick.stream.bind(magick));
|
||||||
|
|
||||||
|
@ -72,11 +73,14 @@ async function placeholderImage(width, height) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
labelText = labelText || `${width} x ${height}`;
|
||||||
|
labelColor = labelColor || '#B0B0B0';
|
||||||
|
|
||||||
// text
|
// text
|
||||||
magick
|
magick
|
||||||
.fill('#B0B0B0')
|
.fill(labelColor)
|
||||||
.fontSize(20)
|
.fontSize(20)
|
||||||
.drawText(0, 0, width + ' x ' + height, 'center');
|
.drawText(0, 0, labelText, 'center');
|
||||||
|
|
||||||
const stream = await streamAsync('png');
|
const stream = await streamAsync('png');
|
||||||
|
|
||||||
|
@ -156,6 +160,17 @@ function getRouter(appType) {
|
||||||
// This is a fallback to versafix-1 if the block thumbnail is not defined by the template
|
// This is a fallback to versafix-1 if the block thumbnail is not defined by the template
|
||||||
router.use('/templates/:mosaicoTemplateId/edres', express.static(path.join(__dirname, '..', '..', 'client', 'static', 'mosaico', 'templates', 'versafix-1', 'edres')));
|
router.use('/templates/:mosaicoTemplateId/edres', express.static(path.join(__dirname, '..', '..', 'client', 'static', 'mosaico', 'templates', 'versafix-1', 'edres')));
|
||||||
|
|
||||||
|
// This is the final fallback for a block thumbnail, so that at least something gets returned
|
||||||
|
router.getAsync('/templates/:mosaicoTemplateId/edres/:fileName', async (req, res, next) => {
|
||||||
|
let labelText = req.params.fileName.replace(/\.png$/, '');
|
||||||
|
labelText = labelText.replace(/[_]/g, ' ');
|
||||||
|
labelText = capitalize.words(labelText);
|
||||||
|
|
||||||
|
const image = await placeholderImage(340, 100, labelText, '#ffffff');
|
||||||
|
res.set('Content-Type', 'image/' + image.format);
|
||||||
|
image.stream.pipe(res);
|
||||||
|
});
|
||||||
|
|
||||||
fileHelpers.installUploadHandler(router, '/upload/:type/:entityId', files.ReplacementBehavior.RENAME, null, 'file', resp => {
|
fileHelpers.installUploadHandler(router, '/upload/:type/:entityId', files.ReplacementBehavior.RENAME, null, 'file', resp => {
|
||||||
return {
|
return {
|
||||||
files: resp.files.map(f => ({name: f.name, url: f.url, size: f.size, thumbnailUrl: f.thumbnailUrl}))
|
files: resp.files.map(f => ({name: f.name, url: f.url, size: f.size, thumbnailUrl: f.thumbnailUrl}))
|
||||||
|
|
|
@ -1532,10 +1532,218 @@ const versafix = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||||
'</body>\n' +
|
'</body>\n' +
|
||||||
'</html>\n';
|
'</html>\n';
|
||||||
|
|
||||||
|
const mjmlSample = '<mjml>\n' +
|
||||||
|
' <mj-head>\n' +
|
||||||
|
' <mj-attributes>\n' +
|
||||||
|
' <mj-body background-color="white"/>\n' +
|
||||||
|
' <mj-section padding="0px 0px" />\n' +
|
||||||
|
' <mj-text padding="0px 10px" />\n' +
|
||||||
|
' <mj-image padding="10px 10px" alt="" />\n' +
|
||||||
|
' <mj-mosaico-image padding="10px 10px" alt="" />\n' +
|
||||||
|
' <mj-mosaico-button align="left" background-color="#e85034" color="#fff" border-radius="24px" font-size="11px" />\n' +
|
||||||
|
' \n' +
|
||||||
|
' <mj-class name="header-section" margin-top="10px" background-color="#e85034" padding-top="5px" padding-bottom="5px" full-width="full-width" css-class="header"/>\n' +
|
||||||
|
'\n' +
|
||||||
|
' <mj-class name="banner-section" padding-top="10px" />\n' +
|
||||||
|
'\n' +
|
||||||
|
' <mj-class name="feature-section" padding-top="10px" padding-bottom="15px" css-class="feature" />\n' +
|
||||||
|
' \n' +
|
||||||
|
' <mj-class name="divider-section" background-color="#e85034" vertical-align="middle" full-width="full-width" padding-top="10px" padding-bottom="5px" css-class="divider"/>\n' +
|
||||||
|
'\n' +
|
||||||
|
' <mj-class name="article-section" padding-top="10px" padding-bottom="10px" css-class="article" />\n' +
|
||||||
|
'\n' +
|
||||||
|
' <mj-class name="links-section" padding-top="0px" padding-bottom="0px" background-color="#e85034" vertical-align="middle" full-width="full-width" />\n' +
|
||||||
|
' <mj-social font-size="12px" font-family="arial,helvetica neue,helvetica,sans-serif" icon-size="30px" mode="horizontal" />\n' +
|
||||||
|
' <mj-social-element text-padding="4px 15px 4px 0px" padding="8px" alt="" color="white"/>\n' +
|
||||||
|
' \n' +
|
||||||
|
' <mj-class name="footer-section" padding-top="30px"/>\n' +
|
||||||
|
' <mj-class name="footer-text" css-class="footer" />\n' +
|
||||||
|
' </mj-attributes>\n' +
|
||||||
|
' \n' +
|
||||||
|
' <mj-mosaico-property property-id="leftImage" label="Left Image" type="image" />\n' +
|
||||||
|
' <mj-mosaico-property property-id="middleImage" label="Middle Image" type="image" />\n' +
|
||||||
|
' <mj-mosaico-property property-id="rightImage" label="Right Image" type="image" />\n' +
|
||||||
|
' <mj-mosaico-property property-id="readMoreLink" label="Button" type="link" />\n' +
|
||||||
|
' \n' +
|
||||||
|
' <mj-style>\n' +
|
||||||
|
' p {\n' +
|
||||||
|
' font-family: Ubuntu, Helvetica, Arial, sans-serif, Helvetica, Arial, sans-serif;\n' +
|
||||||
|
' font-size: 12px;\n' +
|
||||||
|
' color: #9da3a3;\n' +
|
||||||
|
' margin-top: 8px;\n' +
|
||||||
|
' }\n' +
|
||||||
|
' \n' +
|
||||||
|
' h2 {\n' +
|
||||||
|
' margin: 5px 0px 0px 0px;\n' +
|
||||||
|
' font-size: 15px;\n' +
|
||||||
|
' font-weight: normal;\n' +
|
||||||
|
' }\n' +
|
||||||
|
' \n' +
|
||||||
|
' .header a {\n' +
|
||||||
|
' text-decoration: none;\n' +
|
||||||
|
' color: white;\n' +
|
||||||
|
' }\n' +
|
||||||
|
' \n' +
|
||||||
|
' .feature p {\n' +
|
||||||
|
' text-align: center;\n' +
|
||||||
|
' }\n' +
|
||||||
|
' \n' +
|
||||||
|
' .feature h2 {\n' +
|
||||||
|
' color: #e85034;\n' +
|
||||||
|
' text-align: center;\n' +
|
||||||
|
' }\n' +
|
||||||
|
' \n' +
|
||||||
|
' .divider h2 {\n' +
|
||||||
|
' color: white;\n' +
|
||||||
|
' text-align: center;\n' +
|
||||||
|
' }\n' +
|
||||||
|
' \n' +
|
||||||
|
' .divider p {\n' +
|
||||||
|
' color: #f8d5d1;\n' +
|
||||||
|
' text-align: center;\n' +
|
||||||
|
' }\n' +
|
||||||
|
'\n' +
|
||||||
|
' .article h2 {\n' +
|
||||||
|
' font-weight: bold;\n' +
|
||||||
|
' margin-top: 10px;\n' +
|
||||||
|
' }\n' +
|
||||||
|
' \n' +
|
||||||
|
' .article p {\n' +
|
||||||
|
' color: #45474e;\n' +
|
||||||
|
' }\n' +
|
||||||
|
'\n' +
|
||||||
|
' .footer a {\n' +
|
||||||
|
' color: #3A3A3A;\n' +
|
||||||
|
' }\n' +
|
||||||
|
'\n' +
|
||||||
|
' .footer p {\n' +
|
||||||
|
' font-family: arial,helvetica neue,helvetica,sans-serif;\n' +
|
||||||
|
' font-size: 12px;\n' +
|
||||||
|
' text-align: center;\n' +
|
||||||
|
' }\n' +
|
||||||
|
' </mj-style>\n' +
|
||||||
|
' </mj-head>\n' +
|
||||||
|
' \n' +
|
||||||
|
' <mj-body>\n' +
|
||||||
|
' \n' +
|
||||||
|
' <mj-section mj-class="header-section">\n' +
|
||||||
|
' <mj-column>\n' +
|
||||||
|
' <mj-text align="left"><a href="https://lists.example.org/subscription/[LIST_ID]?locale=en-US">Subscribe</a></mj-text>\n' +
|
||||||
|
' </mj-column>\n' +
|
||||||
|
' <mj-column>\n' +
|
||||||
|
' <mj-text align="right"><a href="[LINK_BROWSER]">View in browser</a></mj-text>\n' +
|
||||||
|
' </mj-column>\n' +
|
||||||
|
' </mj-section>\n' +
|
||||||
|
' \n' +
|
||||||
|
' <mj-mosaico-block block-id="banner" label="Banner">\n' +
|
||||||
|
' <mj-section mj-class="banner-section">\n' +
|
||||||
|
' <mj-column>\n' +
|
||||||
|
' <mj-mosaico-image property-id="image" placeholder-height="400" href="https://www.example.com/xxx" />\n' +
|
||||||
|
' </mj-column>\n' +
|
||||||
|
' </mj-section>\n' +
|
||||||
|
' </mj-mosaico-block>\n' +
|
||||||
|
'\n' +
|
||||||
|
' <mj-mosaico-container>\n' +
|
||||||
|
' \n' +
|
||||||
|
' <mj-mosaico-block block-id="feature_section" label="Feature">\n' +
|
||||||
|
' <mj-section mj-class="feature-section">\n' +
|
||||||
|
' <mj-column>\n' +
|
||||||
|
' <mj-mosaico-image property-id="leftImage" placeholder-height="150" href-editable="true" />\n' +
|
||||||
|
' <mj-text>\n' +
|
||||||
|
' <h2 mj-mosaico-editable="leftTitleText">Lorem ipsum dolor</h2>\n' +
|
||||||
|
' <div mj-mosaico-editable="leftBodyText">\n' +
|
||||||
|
' <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eleifend sagittis nunc, et fermentum est ullamcorper dignissim.</p>\n' +
|
||||||
|
' </div>\n' +
|
||||||
|
' </mj-text>\n' +
|
||||||
|
' </mj-column>\n' +
|
||||||
|
' <mj-column>\n' +
|
||||||
|
' <mj-mosaico-image property-id="middleImage" placeholder-height="150" href-editable="true" />\n' +
|
||||||
|
' <mj-text>\n' +
|
||||||
|
' <h2 mj-mosaico-editable="middleTitleText">Lorem ipsum dolor</h2>\n' +
|
||||||
|
' <div mj-mosaico-editable="leftBodyText">\n' +
|
||||||
|
' <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eleifend sagittis nunc, et fermentum est ullamcorper dignissim.</p>\n' +
|
||||||
|
' </div>\n' +
|
||||||
|
' </mj-text>\n' +
|
||||||
|
' </mj-column>\n' +
|
||||||
|
' <mj-column>\n' +
|
||||||
|
' <mj-mosaico-image property-id="rightImage" placeholder-height="150" href-editable="true" />\n' +
|
||||||
|
' <mj-text>\n' +
|
||||||
|
' <h2 mj-mosaico-editable="rightTitleText">Lorem ipsum dolor</h2>\n' +
|
||||||
|
' <div mj-mosaico-editable="leftBodyText">\n' +
|
||||||
|
' <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eleifend sagittis nunc, et fermentum est ullamcorper dignissim.</p>\n' +
|
||||||
|
' </div>\n' +
|
||||||
|
' </mj-text>\n' +
|
||||||
|
' </mj-column>\n' +
|
||||||
|
' </mj-section>\n' +
|
||||||
|
' </mj-mosaico-block>\n' +
|
||||||
|
'\n' +
|
||||||
|
' <mj-mosaico-block block-id="divider_section" label="Divider">\n' +
|
||||||
|
' <mj-section mj-class="divider-section">\n' +
|
||||||
|
' <mj-column>\n' +
|
||||||
|
' <mj-text>\n' +
|
||||||
|
' <h2 mj-mosaico-editable="titleText">Lorem ipsum dolor</h2>\n' +
|
||||||
|
' </mj-text>\n' +
|
||||||
|
' <mj-divider border-color="white" border-width="1px" padding-bottom="10px" padding-top="15px"></mj-divider>\n' +
|
||||||
|
' <mj-text>\n' +
|
||||||
|
' <div mj-mosaico-editable="bodyText">\n' +
|
||||||
|
' <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.</p>\n' +
|
||||||
|
' </div>\n' +
|
||||||
|
' </mj-text>\n' +
|
||||||
|
' </mj-column>\n' +
|
||||||
|
' </mj-section>\n' +
|
||||||
|
' </mj-mosaico-block> \n' +
|
||||||
|
' \n' +
|
||||||
|
' <mj-mosaico-block block-id="article_section" label="Article">\n' +
|
||||||
|
' <mj-section mj-class="article-section">\n' +
|
||||||
|
' <mj-column>\n' +
|
||||||
|
' <mj-mosaico-image property-id="image" placeholder-height="280" href-editable="true" />\n' +
|
||||||
|
' </mj-column>\n' +
|
||||||
|
' <mj-column>\n' +
|
||||||
|
' <mj-text>\n' +
|
||||||
|
' <h2 mj-mosaico-editable="titleText">Lorem ipsum dolor</h2>\n' +
|
||||||
|
' <div mj-mosaico-editable="bodyText">\n' +
|
||||||
|
' <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.</p>\n' +
|
||||||
|
' </div>\n' +
|
||||||
|
' </mj-text>\n' +
|
||||||
|
' <mj-mosaico-button property-id="readMoreLink" font-family="Ubuntu, Helvetica, Arial, sans-serif, Helvetica, Arial, sans-serif" padding-left="10px" padding-bottom="15px" padding-top="15px">Read more ...</mj-mosaico-button>\n' +
|
||||||
|
' </mj-column>\n' +
|
||||||
|
' </mj-section>\n' +
|
||||||
|
' </mj-mosaico-block> \n' +
|
||||||
|
' \n' +
|
||||||
|
' </mj-mosaico-container> \n' +
|
||||||
|
'\n' +
|
||||||
|
' <mj-section mj-class="links-section">\n' +
|
||||||
|
' <mj-column>\n' +
|
||||||
|
' <mj-social border-radius="5px">\n' +
|
||||||
|
' <mj-social-element name="facebook" href="[LINK_BROWSER]">Share on Facebook</mj-social-element>\n' +
|
||||||
|
' <mj-social-element name="twitter" href="[LINK_BROWSER]">Tweet</mj-social-element>\n' +
|
||||||
|
' </mj-social> \n' +
|
||||||
|
' </mj-column>\n' +
|
||||||
|
' </mj-section>\n' +
|
||||||
|
' \n' +
|
||||||
|
' <mj-section mj-class="footer-section">\n' +
|
||||||
|
' <mj-column>\n' +
|
||||||
|
' <mj-text mj-class="footer-text">\n' +
|
||||||
|
' <p>This email was sent to <a href="mailto:[EMAIL]">[EMAIL]</a><p>\n' +
|
||||||
|
' <p> <a href="[LINK_UNSUBSCRIBE]">Unsubscribe from this list</a> <a href="[LINK_PREFERENCES]">Update subscription preferences</a> </p>\n' +
|
||||||
|
' <p>Your address XXXXXX</p>\n' +
|
||||||
|
' </mj-text>\n' +
|
||||||
|
' </mj-column>\n' +
|
||||||
|
' </mj-section>\n' +
|
||||||
|
' \n' +
|
||||||
|
' </mj-body>\n' +
|
||||||
|
'</mjml>';
|
||||||
|
|
||||||
|
|
||||||
function getVersafix() {
|
function getVersafix() {
|
||||||
return versafix;
|
return versafix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getMJMLSample() {
|
||||||
|
return mjmlSample;
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getVersafix
|
getVersafix,
|
||||||
|
getMJMLSample
|
||||||
};
|
};
|
Loading…
Add table
Add a link
Reference in a new issue