mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-01 15:29:19 +03:00
Updated brand settings modal to use new preview
- the new preview mode doesn't require settings to be saved in advance - TODO: prevent interaction with the iframe a la portal Notes: - this works by sending a post message to the frontend with a custom header - generated HTML is loaded into the iframe using postMessage - we can possibly write the HTML direct to the iframe - something to experiment with later
This commit is contained in:
parent
c54e1dc2c5
commit
e75720d390
@ -2,8 +2,28 @@
|
||||
<div class="gh-branding-settings-header">
|
||||
<h4>Branding</h4>
|
||||
<div class="gh-branding-settings-actions">
|
||||
<a class="gh-btn gh-btn-primary" href="" role="button" title="Close" {{action "closeModal"}}><span>Save and close</span></a>
|
||||
<button
|
||||
class="gh-btn mr3"
|
||||
{{action "closeModal"}}
|
||||
{{!-- disable mouseDown so it doesn't trigger focus-out validations --}}
|
||||
{{on "mousedown" (optional this.noop)}}
|
||||
data-test-button="cancel-custom-view-form"
|
||||
>
|
||||
<span>Cancel</span>
|
||||
</button>
|
||||
<GhTaskButton
|
||||
@buttonText="Save and close"
|
||||
@successText="Saved"
|
||||
@task={{this.saveTask}}
|
||||
@idleClass="gh-btn-primary"
|
||||
@class="gh-btn gh-btn-icon"
|
||||
data-test-button="save-members-modal-setting"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<div class="gh-branding-settings">
|
||||
<section class="gh-branding-settings-options">
|
||||
@ -164,8 +184,12 @@
|
||||
</section>
|
||||
|
||||
<section class="gh-branding-settings-right">
|
||||
<GhBrowserPreview class="gh-branding-settings-previewcontainer" @icon={{this.settings.icon}} @title={{this.config.blogTitle}}>
|
||||
<GhSiteIframe class="gh-branding-settings-preview" @guid={{this.previewGuid}}></GhSiteIframe>
|
||||
<GhBrowserPreview class="gh-branding-settings-previewcontainer" @icon={{this.icon}} @title={{this.config.blogTitle}}>
|
||||
<GhSiteIframe
|
||||
class="gh-branding-settings-preview"
|
||||
@src={{this.themePreviewUrl}}
|
||||
@guid={{this.previewGuid}}
|
||||
></GhSiteIframe>
|
||||
</GhBrowserPreview>
|
||||
</section>
|
||||
</div>
|
||||
|
@ -20,16 +20,27 @@ export default ModalComponent.extend({
|
||||
notifications: service(),
|
||||
session: service(),
|
||||
settings: service(),
|
||||
ajax: service(),
|
||||
|
||||
imageExtensions: IMAGE_EXTENSIONS,
|
||||
imageMimeTypes: IMAGE_MIME_TYPES,
|
||||
iconExtensions: null,
|
||||
iconMimeTypes: 'image/png,image/x-icon',
|
||||
|
||||
dirtyAttributes: false,
|
||||
|
||||
previewGuid: (new Date()).valueOf(),
|
||||
|
||||
frontendUrl: computed('config.blogUrl', function () {
|
||||
return `${this.get('config.blogUrl')}`;
|
||||
}),
|
||||
|
||||
themePreviewUrl: computed(function () {
|
||||
let origin = window.location.origin;
|
||||
let subdir = this.ghostPaths.subdir;
|
||||
let url = this.ghostPaths.url.join(origin, subdir);
|
||||
|
||||
return url.replace(/\/$/, '/ghost/preview/');
|
||||
}),
|
||||
|
||||
accentColorPickerValue: computed('settings.accentColor', function () {
|
||||
return this.get('settings.accentColor') || '#ffffff';
|
||||
}),
|
||||
@ -46,10 +57,23 @@ export default ModalComponent.extend({
|
||||
return htmlSafe(`background-color: ${this.accentColorPickerValue}`);
|
||||
}),
|
||||
|
||||
getPreviewData: computed('settings.{accentColor,icon,logo,coverImage}', function () {
|
||||
let string = `c=${encodeURIComponent(this.get('settings.accentColor'))}&icon=${encodeURIComponent(this.get('settings.icon'))}&logo=${encodeURIComponent(this.get('settings.logo'))}&cover=${encodeURIComponent(this.get('settings.coverImage'))}`;
|
||||
|
||||
return string;
|
||||
}),
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
this.iconExtensions = ICON_EXTENSIONS;
|
||||
this.refreshPreview();
|
||||
},
|
||||
|
||||
didInsertElement() {
|
||||
window.addEventListener('message', (event) => {
|
||||
if (event && event.data && event.data === 'loaded') {
|
||||
this.replacePreview();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
@ -92,7 +116,6 @@ export default ModalComponent.extend({
|
||||
|
||||
// roll back changes on settings props
|
||||
settings.rollbackAttributes();
|
||||
this.set('dirtyAttributes', false);
|
||||
|
||||
return transition.retry();
|
||||
},
|
||||
@ -102,7 +125,6 @@ export default ModalComponent.extend({
|
||||
async removeImage(image) {
|
||||
// setting `null` here will error as the server treats it as "null"
|
||||
this.settings.set(image, '');
|
||||
await this.save.perform();
|
||||
this.refreshPreview();
|
||||
},
|
||||
|
||||
@ -130,7 +152,6 @@ export default ModalComponent.extend({
|
||||
async imageUploaded(property, results) {
|
||||
if (results[0]) {
|
||||
let result = this.settings.set(property, results[0].url);
|
||||
await this.save.perform();
|
||||
this.refreshPreview();
|
||||
return result;
|
||||
}
|
||||
@ -141,18 +162,48 @@ export default ModalComponent.extend({
|
||||
}
|
||||
},
|
||||
|
||||
replacePreview() {
|
||||
const ghostFrontendUrl = this.frontendUrl;
|
||||
|
||||
const options = {
|
||||
contentType: 'text/html;charset=utf-8',
|
||||
// ember-ajax will try and parse the response as JSON if not explicitly set
|
||||
dataType: 'text',
|
||||
headers: {
|
||||
'x-ghost-preview': this.getPreviewData
|
||||
}
|
||||
};
|
||||
|
||||
this.ajax
|
||||
.post(ghostFrontendUrl, options)
|
||||
.then((response) => {
|
||||
this.getPreviewIframe().contentWindow.postMessage(response, '*');
|
||||
})
|
||||
.catch(() => {
|
||||
this.notifications.showAlert('Sorry, there was an error with preview. Please let the Ghost team know what happened.', {type: 'error'});
|
||||
});
|
||||
},
|
||||
|
||||
refreshPreview() {
|
||||
// this.set('previewGuid',(new Date()).valueOf());
|
||||
// REset the src and trigger a reload
|
||||
this.getPreviewIframe().src = this.themePreviewUrl;
|
||||
},
|
||||
getPreviewIframe() {
|
||||
return document.getElementById('site-frame');
|
||||
},
|
||||
|
||||
debounceUpdateAccentColor: task(function* (event) {
|
||||
yield timeout(500);
|
||||
this._updateAccentColor(event);
|
||||
}).restartable(),
|
||||
|
||||
save: task(function* () {
|
||||
saveTask: task(function* () {
|
||||
let notifications = this.notifications;
|
||||
let validationPromises = [];
|
||||
|
||||
try {
|
||||
yield RSVP.all(validationPromises);
|
||||
this.set('dirtyAttributes', false);
|
||||
return yield this.settings.save();
|
||||
} catch (error) {
|
||||
if (error) {
|
||||
@ -177,7 +228,6 @@ export default ModalComponent.extend({
|
||||
|
||||
// clear out the accent color
|
||||
this.settings.set('accentColor', '');
|
||||
await this.save.perform();
|
||||
this.refreshPreview();
|
||||
return;
|
||||
}
|
||||
@ -197,16 +247,12 @@ export default ModalComponent.extend({
|
||||
}
|
||||
|
||||
this.set('settings.accentColor', newColor);
|
||||
await this.save.perform();
|
||||
this.refreshPreview();
|
||||
} else {
|
||||
this.get('settings.errors').add('accentColor', 'The colour should be in valid hex format');
|
||||
this.get('settings.hasValidated').pushObject('accentColor');
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
refreshPreview() {
|
||||
this.set('previewGuid',(new Date()).valueOf());
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -6,17 +6,19 @@ export default Controller.extend({
|
||||
|
||||
settings: service(),
|
||||
|
||||
queryParams: ['showPortalSettings', 'showBrandingModal'],
|
||||
|
||||
showPortalSettings: false,
|
||||
showBrandingModal: false,
|
||||
showLeaveSettingsModal: false,
|
||||
|
||||
tagName: '',
|
||||
|
||||
|
||||
actions: {
|
||||
openStripeSettings() {
|
||||
this.set('membersStripeOpen', true);
|
||||
},
|
||||
|
||||
|
||||
closePortalSettings() {
|
||||
const changedAttributes = this.settings.changedAttributes();
|
||||
if (changedAttributes && Object.keys(changedAttributes).length > 0) {
|
||||
@ -41,4 +43,4 @@ export default Controller.extend({
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user