Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved post preview design #22113

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const Sidebar: React.FC<SidebarProps> = ({
}) => {
const visibilityCheckboxes = [
{
label: 'Logged out visitors',
label: 'Anonymous visitors',
onChange: (e:boolean) => {
toggleVisibility('visitors', e);
},
Expand Down
78 changes: 59 additions & 19 deletions ghost/admin/app/components/editor/modals/preview.hbs
Original file line number Diff line number Diff line change
@@ -1,29 +1,78 @@
<div class="flex flex-column h-100">
<div class="gh-post-preview-modal">
<header class="modal-header gh-post-preview-header" data-test-modal="preview-email">
<div class="left">
<button class="gh-btn-editor gh-editor-back-button" title="Close" type="button" {{on "click" @close}}>
<span>{{svg-jar "arrow-left"}} Editor</span>
</button>
<h2>Preview</h2>
</div>
<div class="gh-post-preview-btn-group">
<div class="gh-contentfilter gh-btn-group">
<button type="button" class="gh-btn {{if (eq this.tab "browser") "gh-btn-group-selected"}} gh-post-preview-mode" {{on "click" (fn this.changeTab "browser")}}><span>{{svg-jar "desktop"}}</span></button>
<button type="button" class="gh-btn {{if (eq this.tab "mobile") "gh-btn-group-selected"}} gh-post-preview-mode" {{on "click" (fn this.changeTab "mobile")}}><span>{{svg-jar "mobile-phone"}}</span></button>
<button type="button" class="gh-btn gh-post-preview-mode {{if (or (eq this.tab "browser") (eq this.tab "mobile")) "gh-btn-group-selected"}}" {{on "click" (fn this.changeTab "browser")}}><span>Web</span></button>
{{#if (and (not-eq this.settings.membersSignupAccess "none") (not-eq this.settings.editorDefaultEmailRecipients "disabled"))}}
{{#if (and @data.publishOptions.post.isPost (not @data.publishOptions.user.isContributor))}}
<button type="button" class="gh-btn {{if (eq this.tab "email") "gh-btn-group-selected"}} gh-post-preview-mode" {{on "click" (fn this.changeTab "email")}} data-test-button="email-preview"><span>{{svg-jar "email-unread"}}</span></button>
<button type="button" class="gh-btn {{if (eq this.tab "email") "gh-btn-group-selected"}} gh-post-preview-mode" {{on "click" (fn this.changeTab "email")}} data-test-button="email-preview"><span>Email</span></button>
{{/if}}
{{/if}}
<button type="button" class="gh-btn {{if (eq this.tab "social") "gh-btn-group-selected"}} gh-post-preview-mode" {{on "click" (fn this.changeTab "social")}}><span>{{svg-jar "facebook-logo"}}</span></button>
</div>
<div class="gh-contentfilter-divider"></div>
<div class="gh-contentfilter gh-btn-group">
<button type="button" class="gh-btn {{if (or (eq this.tab "browser") (eq this.tab "email")) "gh-btn-group-selected"}} gh-post-preview-mode" {{on "click" (fn this.changeTab "browser")}}><span>{{svg-jar "laptop"}}</span></button>
<button type="button" class="gh-btn {{if (eq this.tab "mobile") "gh-btn-group-selected"}} gh-post-preview-mode" {{on "click" (fn this.changeTab "mobile")}}><span>{{svg-jar "mobile-phone"}}</span></button>
</div>
<div class="gh-contentfilter-divider"></div>
<span class="gh-select gh-web-preview-segment">
<PowerSelect
@selected={{hash value="free" label="Free member"}}
@options={{if (eq this.tab "email")
(array
(hash value="free" label="Free member")
(hash value="paid" label="Paid member")
)
(array
(hash value="anonymous" label="Anonymous")
(hash value="free" label="Free member")
(hash value="paid" label="Paid member")
)
}}
@onChange={{this.noop}}
@triggerComponent={{component "gh-power-select/trigger"}}
@triggerClass="gh-preview-segment-trigger"
@dropdownClass="gh-preview-segment-dropdown"
as |option|
>
{{option.label}}
</PowerSelect>
</span>
</div>
<div class="right">
<div class="gh-post-test-email-group">
<GhDropdownButton
@dropdownName="post-preview-test-email"
@classNames="gh-btn gh-btn-preview gh-post-preview-url"
data-test-button="post-preview-test-email"
>
<span>{{svg-jar "share"}}</span>
</GhDropdownButton>
<GhDropdown
@name="post-preview-test-email"
@classNames="dropdown-menu gh-post-preview-share-dropdown"
@onOpen={{this.focusInput}}
>
<div class="gh-post-preview-share">
<button type="button" {{on "click" (perform this.copyPreviewUrl)}} class="gh-btn gh-btn-icon gh-btn-preview gh-post-copy-url">
<span>{{svg-jar "link"}}Copy draft link</span>
</button>
<a href={{@post.previewUrl}} target="_blank" rel="noopener noreferrer" class="gh-btn gh-btn-preview gh-publish-preview-newtab">
<span>{{svg-jar "external"}}Open in new tab</span>
</a>
</div>
</GhDropdown>
</div>
<div class="gh-contentfilter-divider"></div>
<button
type="button"
class="gh-btn gh-btn-editor gh-editor-preview-trigger active"
{{on "click" @close}}
>
<span>Preview</span>
<span>Close</span>
</button>

{{#if @data.publishOptions.user.isContributor}}
Expand All @@ -36,14 +85,12 @@
{{else}}
<button
type="button"
class="gh-btn gh-btn-editor darkgrey gh-publish-trigger"
class="gh-btn gh-btn-primary"
{{on "click" @data.togglePreviewPublish}}
>
<span>Publish</span>
</button>
{{/if}}

<div class="settings-menu-toggle-spacer"></div>
</div>
</header>

Expand Down Expand Up @@ -74,12 +121,5 @@
/>
{{/if}}
{{/unless}}

{{#if (eq this.tab "social")}}
<Editor::Modals::Preview::Social
@post={{@data.publishOptions.post}}
@skipAnimation={{this.skipAnimation}}
/>
{{/if}}
{{/if}}
</div>
19 changes: 18 additions & 1 deletion ghost/admin/app/components/editor/modals/preview.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import Component from '@glimmer/component';
import copyTextToClipboard from 'ghost-admin/utils/copy-text-to-clipboard';
import {action} from '@ember/object';
import {inject as service} from '@ember/service';
import {task} from 'ember-concurrency';
import {task, timeout} from 'ember-concurrency';
import {tracked} from '@glimmer/tracking';

export default class EditorPostPreviewModal extends Component {
Expand All @@ -16,6 +17,7 @@ export default class EditorPostPreviewModal extends Component {

@tracked tab = this.args.data.currentTab || 'browser';
@tracked isChangingTab = false;
@tracked previewEmailAddress = this.session.user.email;

constructor() {
super(...arguments);
Expand All @@ -33,6 +35,13 @@ export default class EditorPostPreviewModal extends Component {
this.args.data.changeTab?.(tab);
}

@action
focusInput() {
setTimeout(() => {
document.querySelector('[data-post-preview-email-input]')?.focus();
}, 100);
}

@task
*saveFirstTask() {
const {saveTask, publishOptions, hasDirtyAttributes} = this.args.data;
Expand All @@ -45,4 +54,12 @@ export default class EditorPostPreviewModal extends Component {
yield saveTask.perform();
}
}

@task
*copyPreviewUrl() {
copyTextToClipboard(this.args.post.previewUrl);
yield timeout(this.isTesting ? 50 : 3000);
}

noop() {}
}
25 changes: 0 additions & 25 deletions ghost/admin/app/components/editor/modals/preview/browser.hbs
Original file line number Diff line number Diff line change
@@ -1,29 +1,4 @@
<div class="gh-post-preview-container gh-post-preview-browser-container {{unless @skipAnimation "fade-in"}}">
<div class="gh-browserpreview-browser">
<div class="tabs">
<ul><li></li><li></li><li></li></ul>
<div>
{{#if (or @icon this.settings.icon)}}
<span class="favicon"><img src={{or @icon this.settings.icon}} alt="icon"></span>
{{else}}
<span class="favicon default">{{svg-jar "default-favicon"}}</span>
{{/if}}
<span class="db truncate w-90">{{@post.previewUrl}}</span>
<button type="button" {{on "click" (perform this.copyPreviewUrl)}} class="gh-post-preview-url">
<span class="green-d1">
{{#if this.copyPreviewUrl.isRunning}}
{{svg-jar "check-circle" class="check v-mid mr1 ml2"}} Copied
{{else}}
{{svg-jar "copy" class="w4 ml3 v-mid fill-darkgrey"}}
{{/if}}
</span>
</button>
<a href={{@post.previewUrl}} target="_blank" rel="noopener noreferrer" class="gh-publish-preview-newtab">
{{svg-jar "external"}}
</a>
</div>
</div>
</div>
<div class="gh-browserpreview-iframecontainer">
<iframe class="gh-pe-iframe" src={{@post.previewUrl}} title="Desktop browser post preview"></iframe>
</div>
Expand Down
126 changes: 55 additions & 71 deletions ghost/admin/app/components/editor/modals/preview/email.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,16 @@
<div class="gh-post-preview-email-header">
<div class="gh-post-preview-email-columns">
<div class="gh-post-preview-email-group">
<div class="gh-email-preview-newsletter-select" data-test-email-preview-newsletter-select-section>
<p>From:</p>
<form class="gh-email-preview-newsletter-select" data-test-email-preview-newsletter-select-section>
<label for="email-preview-newsletter-select">From</label>
{{#if (gt this.newslettersList.length 1)}}
<PowerSelect
@selected={{this.newsletter}}
@options={{this.newslettersList}}
@onChange={{this.setNewsletter}}
@triggerComponent={{component "gh-power-select/trigger"}}
@triggerClass="gh-preview-newsletter-trigger"
@dropdownClass="gh-publish-newsletter-dropdown gh-preview-newsletter-dropdown"
@extra={{concat "<" (sender-email-address this.newsletter.senderEmail) ">"}}
@triggerClass="gh-preview-newsletter-trigger gh-input-x"
@dropdownClass="gh-dropdown-x gh-publish-newsletter-dropdown gh-preview-newsletter-dropdown"
@selectedItemComponent={{component "editor/modals/preview/selected-newsletter-label"}}
data-test-email-preview-newsletter-select
as |option|
Expand All @@ -24,80 +23,65 @@
<p class="gh-preview-newsletter-name">{{this.newsletter.name}} <span
class="gh-preview-email-address">&lt;{{sender-email-address this.newsletter.senderEmail}}&gt;</span></p>
{{/if}}
</div>
<div class="gh-email-preview-newsletter-select" data-test-email-preview-segment-select-section>
<p>To:</p>
{{#if this.paidMembersEnabled}}
<PowerSelect
@selected={{this.selectedSegment}}
@options={{this.segments}}
@onChange={{this.setSegment}}
@triggerComponent={{component "gh-power-select/trigger"}}
@triggerClass="gh-preview-newsletter-trigger"
@dropdownClass="gh-publish-newsletter-dropdown gh-preview-newsletter-dropdown"
data-test-email-preview-segment-select
as |option|
>
<span>{{option.name}}</span>
</PowerSelect>
{{else}}
<p class="gh-preview-newsletter-name">Jamie Larson <span class="gh-preview-email-address">&lt;[email protected]&gt;</span>
</p>
{{/if}}
</div>
</div>

<div class="gh-post-test-email-group">
<GhDropdownButton
@dropdownName="post-preview-test-email"
@classNames="gh-btn gh-btn-text gh-btn-icon gh-post-preview-email-trigger"
data-test-button="post-preview-test-email"
>
<span>Send test email {{svg-jar "arrow-down-small"}}</span>
</GhDropdownButton>

<GhDropdown
@name="post-preview-test-email"
@classNames="dropdown-menu dropdown-align-right gh-post-preview-email-test-dropdown"
>
<div class="gh-post-preview-email-test">
<Input
@value={{this.previewEmailAddress}}
class="gh-input gh-post-preview-email-input"
placeholder="[email protected]"
aria-label="Email address to receive preview"
aria-invalid={{if this.sendPreviewEmailError "true"}}
aria-describedby={{if this.sendPreviewEmailError "sendError"}}
data-post-preview-email-input
{{on-key "Enter" (perform this.sendPreviewEmailTask)}}
/>

<GhTaskButton
@task={{this.sendPreviewEmailTask}}
@buttonText="Send"
@successText="Sent"
@runningText="Sending..."
@class="gh-btn gh-btn-icon gh-btn-primary"
data-test-button="send-test-email"
/>
</div>

{{#if this.sendPreviewEmailError}}
<div class="gh-post-preview-email-error">
<span class="response" id="sendError">{{this.sendPreviewEmailError}}</span>
</form>
<div class="gh-post-test-email-group">
<GhDropdownButton
@dropdownName="post-preview-test-email"
@classNames="gh-btn gh-btn-icon gh-post-preview-email-trigger"
data-test-button="post-preview-test-email"
>
<span>{{svg-jar "send-email"}}Test</span>
</GhDropdownButton>
<GhDropdown
@name="post-preview-test-email"
@classNames="dropdown-menu gh-post-preview-email-test-dropdown"
@onOpen={{this.focusInput}}
>
<div class="gh-post-preview-email-test">
<form class="form-group">
<label for="post-preview-email-input">Send test email</label>
<Input
@value={{this.previewEmailAddress}}
class="gh-input gh-input-x gh-post-preview-email-input"
placeholder="[email protected]"
aria-label="Email address to receive preview"
aria-invalid={{if this.sendPreviewEmailError "true"}}
aria-describedby={{if this.sendPreviewEmailError "sendError"}}
data-post-preview-email-input
autofocus="true"
{{on-key "Enter" (perform this.sendPreviewEmailTask)}}
/>
<p class="description">You'll receive this as a free member.</p>
<GhTaskButton
@task={{this.sendPreviewEmailTask}}
@buttonText="Send"
@successText="Sent"
@runningText="Sending..."
@class="gh-btn gh-btn-icon gh-btn-primary"
data-test-button="send-test-email"
/>
</form>
</div>
{{/if}}
</GhDropdown>

{{#if this.sendPreviewEmailError}}
<div class="gh-post-preview-email-error">
<span class="response" id="sendError">{{this.sendPreviewEmailError}}</span>
</div>
{{/if}}
</GhDropdown>
</div>
</div>
</div>

<div class="gh-email-preview-newsletter-select" data-test-email-preview-segment-select-section>
<p>Subject:</p>
<hr>

<form class="gh-email-preview-newsletter-select" data-test-email-preview-segment-select-section>
<label for="email-preview-newsletter-select">Subject</label>
<Editor::Modals::Preview::Email::EmailSubject
@post={{@post}}
@savePostTask={{@savePostTask}}
/>
</div>
</form>
</div>
<iframe class="gh-pe-iframe" {{did-insert this.renderEmailPreview}} title="Email preview"
sandbox="allow-same-origin allow-popups allow-popups-to-escape-sandbox"></iframe>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
<div class="gh-email-subject">
{{#if this.isEditing}}
<input
aria-label="Email subject"
type="text"
class="gh-input gh-preview-email-subject-input"
placeholder={{truncate @post.title 40}}
value={{this.subject}}
{{on "blur" this.setSubject}}
{{on-key "Enter" this.setSubject}}
{{autofocus}}
/>
{{else}}
<button class="gh-preview-email-subject" type="button" {{on "click" this.editSubject}}>
{{this.subject}} {{svg-jar "pen"}}
</button>
{{/if}}
<input
aria-label="Email subject"
type="text"
class="gh-input gh-input-x"
placeholder={{truncate @post.title 40}}
value={{this.subject}}
{{on "blur" this.setSubject}}
{{on-key "Enter" this.setSubject}}
/>

<div class="error">
<GhErrorMessage @errors={{@post.errors}} @property="emailSubject" />
Expand Down
Loading
Loading