diff --git a/config/default.toml b/config/default.toml index b824ad53..9e8f065f 100644 --- a/config/default.toml +++ b/config/default.toml @@ -186,6 +186,23 @@ templates=[ ["aves", "MJML Template"] ] +[grapejs.mjml] +# Editor main background color +editorBackgroundColor = "#202835" +# Editor canvas background (light, dark, bluish, custom css) +canvasBackgroundStyle = "bluish" +# Color for the head and attributes labels +canvasLabelsColor = "#4b5666" + +[views.template] + +showeditor = false + +[views.lists] + +statuscolored = false + + [reports] # The whole reporting functionality can be disabled below if the they are not needed and the DB cannot be # properly protected. diff --git a/public/css/flags/flags.css b/public/css/flags/flags.css new file mode 100644 index 00000000..2f31e07e --- /dev/null +++ b/public/css/flags/flags.css @@ -0,0 +1,4 @@ +/*! + * Generated with CSS Flag Sprite generator (https://www.flag-sprites.com/) + */ +.flag{display:inline-block;position: relative;width:16px;height:11px;background:url('/css/flags/flags.png') no-repeat; background-position:-272px -176px;}.flag.flag-gu{background-position:-96px -55px}.flag.flag-mn{background-position:-208px -88px}.flag.flag-va{background-position:-48px -154px}.flag.flag-tibet{background-position:-32px -143px}.flag.flag-fo{background-position:-64px -44px}.flag.flag-th{background-position:-16px -143px}.flag.flag-tr{background-position:-144px -143px}.flag.flag-tl{background-position:-80px -143px}.flag.flag-kz{background-position:-144px -77px}.flag.flag-zm{background-position:-16px -165px}.flag.flag-uz{background-position:-32px -154px}.flag.flag-dk{background-position:-64px -33px}.flag.flag-scotland{background-position:-176px -121px}.flag.flag-gi{background-position:-224px -44px}.flag.flag-gy{background-position:-128px -55px}.flag.flag-bj{background-position:-112px -11px}.flag.flag-fr{background-position:-80px -44px}.flag.flag-mo{background-position:-224px -88px}.flag.flag-ir{background-position:-112px -66px}.flag.flag-io{background-position:-80px -66px}.flag.flag-tm{background-position:-96px -143px}.flag.flag-ch{background-position:-96px -22px}.flag.flag-mt{background-position:-32px -99px}.flag.flag-nl{background-position:-240px -99px}.flag.flag-gp{background-position:-16px -55px}.flag.flag-im{background-position:-48px -66px}.flag.flag-tv{background-position:-176px -143px}.flag.flag-mu{background-position:-48px -99px}.flag.flag-pe{background-position:-96px -110px}.flag.flag-vi{background-position:-112px -154px}.flag.flag-hn{background-position:-176px -55px}.flag.flag-ss{background-position:-128px -132px}.flag.flag-ae{background-position:-16px 0}.flag.flag-td{background-position:-240px -132px}.flag.flag-pw{background-position:0 -121px}.flag.flag-nu{background-position:-32px -110px}.flag.flag-bt{background-position:-208px -11px}.flag.flag-ms{background-position:-16px -99px}.flag.flag-cv{background-position:-240px -22px}.flag.flag-es{background-position:-224px -33px}.flag.flag-mh{background-position:-144px -88px}.flag.flag-la{background-position:-160px -77px}.flag.flag-vn{background-position:-128px -154px}.flag.flag-py{background-position:-16px -121px}.flag.flag-br{background-position:-176px -11px}.flag.flag-ye{background-position:-224px -154px}.flag.flag-ie{background-position:0 -66px}.flag.flag-gh{background-position:-208px -44px}.flag.flag-cg{background-position:-80px -22px}.flag.flag-cu{background-position:-224px -22px}.flag.flag-hu{background-position:-224px -55px}.flag.flag-sg{background-position:-224px -121px}.flag.flag-at{background-position:-176px 0}.flag.flag-lk{background-position:-224px -77px}.flag.flag-vu{background-position:-144px -154px}.flag.flag-bo{background-position:-160px -11px}.flag.flag-jo{background-position:-208px -66px}.flag.flag-er{background-position:-208px -33px}.flag.flag-za{background-position:-256px -154px}.flag.flag-rs{background-position:-80px -121px}.flag.flag-nr{background-position:-16px -110px}.flag.flag-ls{background-position:-256px -77px}.flag.flag-jm{background-position:-192px -66px}.flag.flag-tz{background-position:-208px -143px}.flag.flag-ki{background-position:-16px -77px}.flag.flag-sj{background-position:0 -132px}.flag.flag-cz{background-position:-16px -33px}.flag.flag-pg{background-position:-128px -110px}.flag.flag-lv{background-position:-32px -88px}.flag.flag-do{background-position:-96px -33px}.flag.flag-lu{background-position:-16px -88px}.flag.flag-no{background-position:-256px -99px}.flag.flag-kw{background-position:-112px -77px}.flag.flag-mx{background-position:-96px -99px}.flag.flag-yt{background-position:-240px -154px}.flag.flag-ly{background-position:-48px -88px}.flag.flag-cy{background-position:0 -33px}.flag.flag-ph{background-position:-144px -110px}.flag.flag-my{background-position:-112px -99px}.flag.flag-sm{background-position:-48px -132px}.flag.flag-et{background-position:-240px -33px}.flag.flag-ru{background-position:-96px -121px}.flag.flag-tj{background-position:-48px -143px}.flag.flag-ai{background-position:-64px 0}.flag.flag-pl{background-position:-176px -110px}.flag.flag-kp{background-position:-64px -77px}.flag.flag-uy{background-position:-16px -154px}.flag.flag-gb{background-position:-112px -44px}.flag.flag-gs{background-position:-64px -55px}.flag.flag-kurdistan{background-position:-96px -77px}.flag.flag-rw{background-position:-112px -121px}.flag.flag-ec{background-position:-128px -33px}.flag.flag-mm{background-position:-192px -88px}.flag.flag-pa{background-position:-80px -110px}.flag.flag-wales{background-position:-160px -154px}.flag.flag-kg{background-position:-256px -66px}.flag.flag-ve{background-position:-80px -154px}.flag.flag-tk{background-position:-64px -143px}.flag.flag-ca{background-position:-16px -22px}.flag.flag-is{background-position:-128px -66px}.flag.flag-ke{background-position:-240px -66px}.flag.flag-ro{background-position:-64px -121px}.flag.flag-gq{background-position:-32px -55px}.flag.flag-pt{background-position:-256px -110px}.flag.flag-tf{background-position:-256px -132px}.flag.flag-ad{background-position:0 0}.flag.flag-sk{background-position:-16px -132px}.flag.flag-pm{background-position:-192px -110px}.flag.flag-om{background-position:-64px -110px}.flag.flag-an{background-position:-112px 0}.flag.flag-ws{background-position:-192px -154px}.flag.flag-sh{background-position:-240px -121px}.flag.flag-mp{background-position:-240px -88px}.flag.flag-gt{background-position:-80px -55px}.flag.flag-cf{background-position:-64px -22px}.flag.flag-zanzibar{background-position:0 -165px}.flag.flag-mw{background-position:-80px -99px}.flag.flag-catalonia{background-position:-32px -22px}.flag.flag-ug{background-position:-240px -143px}.flag.flag-je{background-position:-176px -66px}.flag.flag-km{background-position:-32px -77px}.flag.flag-in{background-position:-64px -66px}.flag.flag-bf{background-position:-48px -11px}.flag.flag-mc{background-position:-80px -88px}.flag.flag-sy{background-position:-192px -132px}.flag.flag-sn{background-position:-64px -132px}.flag.flag-kr{background-position:-80px -77px}.flag.flag-eu{background-position:-256px -33px}.flag.flag-bn{background-position:-144px -11px}.flag.flag-st{background-position:-144px -132px}.flag.flag-england{background-position:-192px -33px}.flag.flag-lc{background-position:-192px -77px}.flag.flag-dm{background-position:-80px -33px}.flag.flag-be{background-position:-32px -11px}.flag.flag-ni{background-position:-224px -99px}.flag.flag-ua{background-position:-224px -143px}.flag.flag-mz{background-position:-128px -99px}.flag.flag-pf{background-position:-112px -110px}.flag.flag-tn{background-position:-112px -143px}.flag.flag-ee{background-position:-144px -33px}.flag.flag-xk{background-position:-208px -154px}.flag.flag-sx{background-position:-176px -132px}.flag.flag-sd{background-position:-192px -121px}.flag.flag-gd{background-position:-128px -44px}.flag.flag-ci{background-position:-112px -22px}.flag.flag-sz{background-position:-208px -132px}.flag.flag-cl{background-position:-144px -22px}.flag.flag-fi{background-position:0 -44px}.flag.flag-ga{background-position:-96px -44px}.flag.flag-jp{background-position:-224px -66px}.flag.flag-de{background-position:-32px -33px}.flag.flag-np{background-position:0 -110px}.flag.flag-re{background-position:-48px -121px}.flag.flag-bg{background-position:-64px -11px}.flag.flag-sc{background-position:-160px -121px}.flag.flag-ng{background-position:-208px -99px}.flag.flag-qa{background-position:-32px -121px}.flag.flag-mk{background-position:-160px -88px}.flag.flag-aw{background-position:-208px 0}.flag.flag-kn{background-position:-48px -77px}.flag.flag-al{background-position:-80px 0}.flag.flag-bw{background-position:-240px -11px}.flag.flag-um{background-position:-256px -143px}.flag.flag-ky{background-position:-128px -77px}.flag.flag-tt{background-position:-160px -143px}.flag.flag-so{background-position:-80px -132px}.flag.flag-lt{background-position:0 -88px}.flag.flag-by{background-position:-256px -11px}.flag.flag-bb{background-position:0 -11px}.flag.flag-us{background-position:0 -154px}.flag.flag-md{background-position:-96px -88px}.flag.flag-ag{background-position:-48px 0}.flag.flag-hm{background-position:-160px -55px}.flag.flag-as{background-position:-160px 0}.flag.flag-eg{background-position:-160px -33px}.flag.flag-sv{background-position:-160px -132px}.flag.flag-sl{background-position:-32px -132px}.flag.flag-fk{background-position:-32px -44px}.flag.flag-am{background-position:-96px 0}.flag.flag-ck{background-position:-128px -22px}.flag.flag-tw{background-position:-192px -143px}.flag.flag-kh{background-position:0 -77px}.flag.flag-to{background-position:-128px -143px}.flag.flag-se{background-position:-208px -121px}.flag.flag-cd{background-position:-48px -22px}.flag.flag-pn{background-position:-208px -110px}.flag.flag-gr{background-position:-48px -55px}.flag.flag-id{background-position:-256px -55px}.flag.flag-vc{background-position:-64px -154px}.flag.flag-somaliland{background-position:-96px -132px}.flag.flag-bi{background-position:-96px -11px}.flag.flag-pk{background-position:-160px -110px}.flag.flag-pr{background-position:-224px -110px}.flag.flag-bd{background-position:-16px -11px}.flag.flag-co{background-position:-192px -22px}.flag.flag-fm{background-position:-48px -44px}.flag.flag-bm{background-position:-128px -11px}.flag.flag-ar{background-position:-144px 0}.flag.flag-bv{background-position:-224px -11px}.flag.flag-sb{background-position:-144px -121px}.flag.flag-mq{background-position:-256px -88px}.flag.flag-eh{background-position:-176px -33px}.flag.flag-bh{background-position:-80px -11px}.flag.flag-it{background-position:-144px -66px}.flag.flag-hr{background-position:-192px -55px}.flag.flag-sa{background-position:-128px -121px}.flag.flag-mv{background-position:-64px -99px}.flag.flag-mg{background-position:-128px -88px}.flag.flag-dz{background-position:-112px -33px}.flag.flag-gg{background-position:-192px -44px}.flag.flag-gm{background-position:-256px -44px}.flag.flag-af{background-position:-32px 0}.flag.flag-li{background-position:-208px -77px}.flag.flag-sr{background-position:-112px -132px}.flag.flag-vg{background-position:-96px -154px}.flag.flag-cr{background-position:-208px -22px}.flag.flag-tc{background-position:-224px -132px}.flag.flag-ao{background-position:-128px 0}.flag.flag-ma{background-position:-64px -88px}.flag.flag-mr{background-position:0 -99px}.flag.flag-gn{background-position:0 -55px}.flag.flag-ne{background-position:-176px -99px}.flag.flag-nf{background-position:-192px -99px}.flag.flag-wf{background-position:-176px -154px}.flag.flag-hk{background-position:-144px -55px}.flag.flag-gf{background-position:-160px -44px}.flag.flag-ps{background-position:-240px -110px}.flag.flag-ic{background-position:-240px -55px}.flag.flag-cw{background-position:-256px -22px}.flag.flag-ml{background-position:-176px -88px}.flag.flag-ax{background-position:-224px 0}.flag.flag-gl{background-position:-240px -44px}.flag.flag-dj{background-position:-48px -33px}.flag.flag-cn{background-position:-176px -22px}.flag.flag-ht{background-position:-208px -55px}.flag.flag-lr{background-position:-240px -77px}.flag.flag-tg{background-position:0 -143px}.flag.flag-ba{background-position:-256px 0}.flag.flag-ge{background-position:-144px -44px}.flag.flag-bz{background-position:0 -22px}.flag.flag-au{background-position:-192px 0}.flag.flag-iq{background-position:-96px -66px}.flag.flag-cm{background-position:-160px -22px}.flag.flag-gw{background-position:-112px -55px}.flag.flag-az{background-position:-240px 0}.flag.flag-na{background-position:-144px -99px}.flag.flag-fj{background-position:-16px -44px}.flag.flag-zw{background-position:-32px -165px}.flag.flag-bs{background-position:-192px -11px}.flag.flag-il{background-position:-16px -66px}.flag.flag-nz{background-position:-48px -110px}.flag.flag-me{background-position:-112px -88px}.flag.flag-si{background-position:-256px -121px}.flag.flag-nc{background-position:-160px -99px}.flag.flag-lb{background-position:-176px -77px} \ No newline at end of file diff --git a/public/css/flags/flags.png b/public/css/flags/flags.png new file mode 100644 index 00000000..0658bb8a Binary files /dev/null and b/public/css/flags/flags.png differ diff --git a/public/css/footer.css b/public/css/footer.css index 01f241aa..0ef600d2 100644 --- a/public/css/footer.css +++ b/public/css/footer.css @@ -8,7 +8,7 @@ html { body { /* Margin bottom by footer height */ - margin-bottom: 60px; + margin-bottom: 70px; } .footer { diff --git a/public/css/mailtrain.css b/public/css/mailtrain.css index f4bf6f2f..1aac8abe 100644 --- a/public/css/mailtrain.css +++ b/public/css/mailtrain.css @@ -1,16 +1,28 @@ +@import "flags/flags.css"; + .glyphicon.spinning { animation: spin 1s infinite linear; -webkit-animation: spin2 1s infinite linear; } @keyframes spin { - from { transform: scale(1) rotate(0deg); } - to { transform: scale(1) rotate(360deg); } + from { + transform: scale(1) rotate(0deg); + } + + to { + transform: scale(1) rotate(360deg); + } } @-webkit-keyframes spin2 { - from { -webkit-transform: rotate(0deg); } - to { -webkit-transform: rotate(360deg); } + from { + -webkit-transform: rotate(0deg); + } + + to { + -webkit-transform: rotate(360deg); + } } /* Supporting wider description lists */ @@ -23,11 +35,25 @@ .dl-horizontal dd { margin-left: 220px; } + } +@media screen and (max-width: 767px) { + .text-xs-center { + text-align: center; + } + + .form-group .col-xs-12 button { + margin-bottom: 20px; + } + +} + + h2 .glyphicon { font-size: .75em; } + h3 .glyphicon { font-size: .8em; } @@ -46,4 +72,78 @@ tbody>tr.selected { .row-actions .row-action:last-child { padding-right: 0px; +} + + +span.subscriber-status-1 { + /* subscribed */ + color: #2b5718; +} + +span.subscriber-status-0, +span.subscriber-status-2 { + /* unknow / unsubscribed */ + color: #b3aba0; +} + +span.subscriber-status-3 { + /* bounced */ + color: #aa3203; +} + +span.subscriber-status-4 { + /* complained */ + color: #7b0833; +} + +/* subscriber line status */ +tr.subscriber-status-1 td:first-child { + border-right: solid 3px #87ad77; + text-align:center; + padding-right: 10px; +} + +tr.subscriber-status-0 td:first-child, +tr.subscriber-status-2 td:first-child { + border-right: solid 3px #c7bfb4; + text-align:center; + padding-right: 10px; +} + +tr.subscriber-status-3 td:first-child { + border-right: solid 3px #df6b3d; + text-align:center; + padding-right: 10px; +} + +tr.subscriber-status-4 td:first-child { + border-right: solid 3px #c94475; + text-align:center; + padding-right: 10px; +} + +/* subscribers status icon */ +.status-icon { + display: inline-block; + width: 8px; + height: 8px; + border-radius: 4px; + vertical-align: middle; +} + +.status-icon.subscriber-status-1 { + background-color: #2b5718; +} + +.status-icon.subscriber-status-0, +.status-icon.subscriber-status-2 { + background-color: #b3aba0; +} + +.status-icon.subscriber-status-3 { + background-color: #aa3203; +} + +.status-icon.subscriber-status-4 { + background-color: #7b0833; } \ No newline at end of file diff --git a/routes/lists.js b/routes/lists.js index 516c54d3..0318db12 100644 --- a/routes/lists.js +++ b/routes/lists.js @@ -12,6 +12,7 @@ let forms = require('../lib/models/forms'); let tools = require('../lib/tools'); let striptags = require('striptags'); let htmlescape = require('escape-html'); +let getName = require('country-list').getName; let multer = require('multer'); let os = require('os'); let humanize = require('humanize'); @@ -167,7 +168,7 @@ router.post('/ajax', (req, res) => { '' + row.cid + '', row.subscribers, htmlescape(striptags(row.description) || ''), - '' + _('Edit') + '' ] + ' ' + _('Edit') + '' ] ) }); }); @@ -254,7 +255,7 @@ router.post('/ajax/:id', (req, res) => { } else { return htmlescape(cRow.value || ''); } - })).concat(statuses[row.status]).concat(row.created && row.created.toISOString ? '' + row.created.toISOString() + '' : 'N/A').concat('' + _('Edit') + '')) + })).concat(config.views.lists.statuscolored ? '' + statuses[row.status] + '' : statuses[row.status]).concat(row.created && row.created.toISOString ? '' + row.created.toISOString() + '' : 'N/A').concat('' + _('Edit') + '')) }); }); }); @@ -312,6 +313,7 @@ router.get('/view/:id', passport.csrfProtection, (req, res) => { list.csrfToken = req.csrfToken(); list.customFields = fieldList.filter(field => field.visible); list.customSort = list.customFields.length ? ',' + list.customFields.map(() => '0').join(',') : ''; + list.statusColored = config.views.lists.statuscolored; list.showSubscriptions = req.query.tab === 'subscriptions' || !req.query.tab; list.showImports = req.query.tab === 'imports'; @@ -387,14 +389,27 @@ router.get('/subscription/:id/edit/:cid', passport.csrfProtection, (req, res) => fieldList = []; } + let statuses = [_('Unknown'), _('Subscribed'), _('Unsubscribed'), _('Bounced'), _('Complained')]; + subscription.list = list; subscription.csrfToken = req.csrfToken(); subscription.customFields = fields.getRow(fieldList, subscription, false, true); subscription.useEditor = true; + subscription.createdDate = moment(subscription.created).format('lll'); + subscription.modifiedDate = moment(subscription.statusChange).format('lll'); + + subscription.statusTitle = statuses[subscription.status]; subscription.isSubscribed = subscription.status === 1; subscription.isBounced = subscription.status === 3; + let country = {}; + if (subscription.optInCountry) { + country.name = getName(subscription.optInCountry); + country.code = subscription.optInCountry.toLowerCase(); + } + subscription.country = country; + let tzfound = false; subscription.timezones = moment.tz.names().map(tz => { let selected = false; diff --git a/views/layout.hbs b/views/layout.hbs index 73eff28a..8aad8a19 100644 --- a/views/layout.hbs +++ b/views/layout.hbs @@ -147,7 +147,7 @@ diff --git a/views/lists/subscription/edit.hbs b/views/lists/subscription/edit.hbs index a1db3a24..1cb20de3 100644 --- a/views/lists/subscription/edit.hbs +++ b/views/lists/subscription/edit.hbs @@ -41,12 +41,28 @@
- +
+
+
+ + {{#translate}}Status{{/translate}} {{statusTitle}} + {{#if country.code }} +
+ {{country.name}} + {{/if}} +
+ {{#translate}}Created{{/translate}} {{createdDate}} +
+ {{#translate}}Modified{{/translate}} {{modifiedDate}} +
+
+
+
@@ -163,6 +179,7 @@
+
@@ -177,7 +194,10 @@
-
+
+ +
+
{{#if isSubscribed}} @@ -188,8 +208,7 @@ {{/if}}
- -
+ diff --git a/views/lists/view.hbs b/views/lists/view.hbs index 69a00e3c..ce602ab9 100644 --- a/views/lists/view.hbs +++ b/views/lists/view.hbs @@ -205,3 +205,16 @@ {{/if}}
+{{#if statusColored }} + +{{/if}} \ No newline at end of file