Duplicated email card as email-cta

refs https://github.com/TryGhost/Team/issues/910

- readying the foundation for adding segment selection and CTA config to the `email-cta` card
- will only be available to select from card menus when the `emailCardSegments` feature flag is enabled
This commit is contained in:
Kevin Ansfield 2021-07-20 10:54:19 +01:00
parent 10f83ebd45
commit 463c610e70
4 changed files with 173 additions and 0 deletions

View File

@ -0,0 +1,43 @@
<KoenigCard
@icon="koenig/card-indicator-email"
@class={{concat (kg-style "container-card") " kg-email-card mih10 miw-100 relative"}}
@style={{this.cardStyle}}
@headerOffset={{this.headerOffset}}
@toolbar={{this.toolbar}}
@payload={{this.payload}}
@isSelected={{this.isSelected}}
@isEditing={{this.isEditing}}
@selectCard={{action this.selectCard}}
@deselectCard={{action this.deselectCard}}
@editCard={{action this.editCard}}
@saveCard={{action this.saveCard}}
@saveAsSnippet={{this.saveAsSnippet}}
@onLeaveEdit={{action "leaveEditMode"}}
@addParagraphAfterCard={{this.addParagraphAfterCard}}
@moveCursorToPrevSection={{this.moveCursorToPrevSection}}
@moveCursorToNextSection={{this.moveCursorToNextSection}}
@editor={{this.editor}}
as |card|
>
{{#if this.isEditing}}
<KoenigTextReplacementHtmlInput
@html={{this.payload.html}}
@placeholder="Email only content..."
@autofocus={{true}}
@class="miw-100 bn bg-transparent"
@onChange={{action "updateHtml"}}
@onFocus={{action (mut this.isFocused) true}}
@onBlur={{action (mut this.isFocused) false}}
@didCreateEditor={{action "registerEditor"}}
/>
<div class="kg-card-help">
<p>
<span>Only visible when delivered by email, this card will not be published on your site.</span>
<a href="https://ghost.org/help/email-newsletters/#email-cards" class="dib lh-zero v-mid kg-card-help-icon-link" target="_blank" rel="noreferer nopener">{{svg-jar "help" class="stroke-midgrey"}}</a>
</p>
</div>
{{else}}
<p>{{{this.formattedHtml}}}</p>
<div class="koenig-card-click-overlay"></div>
{{/if}}
</KoenigCard>

View File

@ -0,0 +1,117 @@
import Browser from 'mobiledoc-kit/utils/browser';
import Component from '@ember/component';
import {computed} from '@ember/object';
import {formatTextReplacementHtml} from './koenig-text-replacement-html-input';
import {isBlank} from '@ember/utils';
import {run} from '@ember/runloop';
import {set} from '@ember/object';
export default Component.extend({
// attrs
payload: null,
isSelected: false,
isEditing: false,
// closure actions
selectCard() {},
deselectCard() {},
editCard() {},
saveCard() {},
deleteCard() {},
moveCursorToNextSection() {},
moveCursorToPrevSection() {},
addParagraphAfterCard() {},
registerComponent() {},
formattedHtml: computed('payload.html', function () {
return formatTextReplacementHtml(this.payload.html);
}),
toolbar: computed('isEditing', function () {
if (this.isEditing) {
return false;
}
return {
items: [{
buttonClass: 'fw4 flex items-center white',
icon: 'koenig/kg-edit',
iconClass: 'fill-white',
title: 'Edit',
text: '',
action: run.bind(this, this.editCard)
}]
};
}),
init() {
this._super(...arguments);
this.registerComponent(this);
if (!this.payload.html) {
this._updatePayloadAttr('html', '<p>Hey {first_name, "there"},</p>');
}
},
actions: {
updateHtml(html) {
this._updatePayloadAttr('html', html);
},
registerEditor(textReplacementEditor) {
let commands = {
'META+ENTER': run.bind(this, this._enter, 'meta'),
'CTRL+ENTER': run.bind(this, this._enter, 'ctrl')
};
Object.keys(commands).forEach((str) => {
textReplacementEditor.registerKeyCommand({
str,
run() {
return commands[str](textReplacementEditor, str);
}
});
});
this._textReplacementEditor = textReplacementEditor;
run.scheduleOnce('afterRender', this, this._placeCursorAtEnd);
},
leaveEditMode() {
if (isBlank(this.payload.html)) {
// afterRender is required to avoid double modification of `isSelected`
// TODO: see if there's a way to avoid afterRender
run.scheduleOnce('afterRender', this, this.deleteCard);
}
}
},
_updatePayloadAttr(attr, value) {
let payload = this.payload;
let save = this.saveCard;
set(payload, attr, value);
// update the mobiledoc and stay in edit mode
save(payload, false);
},
/* key commands ----------------------------------------------------------*/
_enter(modifier) {
if (this.isEditing && (modifier === 'meta' || (modifier === 'crtl' && Browser.isWin()))) {
this.editCard();
}
},
_placeCursorAtEnd() {
if (!this._textReplacementEditor) {
return;
}
let tailPosition = this._textReplacementEditor.post.tailPosition();
let rangeToSelect = tailPosition.toRange();
this._textReplacementEditor.selectRange(rangeToSelect);
}
});

View File

@ -12,6 +12,7 @@ export const CARD_COMPONENT_MAP = {
bookmark: 'koenig-card-bookmark',
gallery: 'koenig-card-gallery',
email: 'koenig-card-email',
'email-cta': 'koenig-card-email-cta',
paywall: 'koenig-card-paywall'
};
@ -27,6 +28,7 @@ export const CARD_ICON_MAP = {
bookmark: 'koenig/kg-card-type-bookmark',
gallery: 'koenig/kg-card-type-gallery',
email: 'koenig/kg-card-type-gen-embed',
'email-cta': 'koenig/kg-card-type-gen-embed',
paywall: 'koenig/kg-card-type-divider'
};
@ -45,6 +47,7 @@ export default [
createComponentCard('markdown', {deleteIfEmpty: 'payload.markdown'}),
createComponentCard('gallery', {hasEditMode: false}),
createComponentCard('email', {deleteIfEmpty: 'payload.html'}),
createComponentCard('email-cta', {deleteIfEmpty: 'payload.html'}),
createComponentCard('paywall', {hasEditMode: false, selectAfterInsert: false})
];
@ -118,6 +121,15 @@ export const CARD_MENU = [
type: 'card',
replaceArg: 'email'
},
{
label: 'Email call to action',
icon: 'koenig/kg-card-type-email',
desc: 'Target free or paid members with a CTA',
matches: ['email', 'cta'],
type: 'card',
replaceArg: 'email-cta',
feature: 'emailCardSegments'
},
{
label: 'Public preview',
icon: 'koenig/kg-card-type-paywall',

View File

@ -0,0 +1 @@
export {default} from 'koenig-editor/components/koenig-card-email-cta';