From 7c992825ed3ae1ceede8d1ee8ff2af2c686cd6d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20der=20Winden?= Date: Thu, 22 Aug 2024 16:49:29 +0200 Subject: [PATCH] Publish modal updates (#20817) The new modal for the updated publishing flow has an entirely new layout, based on feedback previously received. In addition, this PR includes a few tweaks to the underlying logic. --- .../editor/modals/publish-flow/confirm.js | 8 +- ghost/admin/app/components/gh-task-button.hbs | 41 +++- ghost/admin/app/components/gh-task-button.js | 1 + .../app/components/modal-post-success.hbs | 223 +++++++++++------- .../app/components/modal-post-success.js | 5 + ghost/admin/app/components/posts-list/list.js | 29 ++- .../app/styles/components/publishmenu.css | 133 ++++++++--- ghost/admin/app/styles/layouts/content.css | 11 +- ghost/admin/public/assets/icons/link.svg | 5 +- 9 files changed, 328 insertions(+), 128 deletions(-) diff --git a/ghost/admin/app/components/editor/modals/publish-flow/confirm.js b/ghost/admin/app/components/editor/modals/publish-flow/confirm.js index 044298bd7a..5950b1b949 100644 --- a/ghost/admin/app/components/editor/modals/publish-flow/confirm.js +++ b/ghost/admin/app/components/editor/modals/publish-flow/confirm.js @@ -96,10 +96,14 @@ export default class PublishFlowOptions extends Component { if (this.feature.publishFlowEndScreen) { if (this.args.publishOptions.isScheduled) { localStorage.setItem('ghost-last-scheduled-post', this.args.publishOptions.post.id); - this.router.transitionTo('posts', {queryParams: {type: 'scheduled'}}); + this.router.transitionTo('posts'); } else { localStorage.setItem('ghost-last-published-post', this.args.publishOptions.post.id); - this.router.transitionTo('posts.analytics', this.args.publishOptions.post.id); + if (this.args.publishOptions.post.emailOnly) { + this.router.transitionTo('posts.analytics', this.args.publishOptions.post.id); + } else { + this.router.transitionTo('posts'); + } } } } catch (e) { diff --git a/ghost/admin/app/components/gh-task-button.hbs b/ghost/admin/app/components/gh-task-button.hbs index 0dac4bd764..0a48b2333e 100644 --- a/ghost/admin/app/components/gh-task-button.hbs +++ b/ghost/admin/app/components/gh-task-button.hbs @@ -6,8 +6,41 @@ isFailure=this.isFailure )}} {{else}} - {{#if this.isRunning}}{{#if this.showIcon}}{{svg-jar "spinner" class="gh-icon-spinner"}} {{/if}}{{this.runningText}}{{/if}} - {{#if this.isIdle}}{{this.buttonText}}{{/if}} - {{#if this.isSuccess}}{{#if this.showIcon}}{{svg-jar "check-circle"}} {{/if}}{{this.successText}}{{/if}} - {{#if this.isFailure}}{{#if this.showIcon}}{{svg-jar "retry"}} {{/if}}{{this.failureText}}{{/if}} + {{#if this.isRunning}} + + {{#if this.showIcon}} + {{svg-jar "spinner" class="gh-icon-spinner"}} + {{/if}} + {{this.runningText}} + + {{/if}} + + {{#if (and this.isIdle (not (or this.isRunning this.isSuccess this.isFailure)))}} + + {{#if this.showIcon}} + {{#if this.idleIcon}} + {{svg-jar this.idleIcon}} + {{/if}} + {{/if}} + {{this.buttonText}} + +{{/if}} + + + {{#if this.isSuccess}} + + {{#if this.showIcon}} + {{svg-jar "check-circle"}} + {{/if}} + {{this.successText}} + + {{/if}} + {{#if this.isFailure}} + + {{#if this.showIcon}} + {{svg-jar "retry"}} + {{/if}} + {{this.failureText}} + + {{/if}} {{/if}} diff --git a/ghost/admin/app/components/gh-task-button.js b/ghost/admin/app/components/gh-task-button.js index f23faeb66c..873c360366 100644 --- a/ghost/admin/app/components/gh-task-button.js +++ b/ghost/admin/app/components/gh-task-button.js @@ -33,6 +33,7 @@ const GhTaskButton = Component.extend({ defaultClick: false, buttonText: 'Save', idleClass: '', + idleIcon: '', runningClass: '', showIcon: true, showSuccess: true, // set to false if you want the spinner to show until a transition occurs diff --git a/ghost/admin/app/components/modal-post-success.hbs b/ghost/admin/app/components/modal-post-success.hbs index 0ce2351e0c..75ba245fbc 100644 --- a/ghost/admin/app/components/modal-post-success.hbs +++ b/ghost/admin/app/components/modal-post-success.hbs @@ -1,18 +1,4 @@ diff --git a/ghost/admin/app/components/modal-post-success.js b/ghost/admin/app/components/modal-post-success.js index 0e58369a29..1de8a27ec7 100644 --- a/ghost/admin/app/components/modal-post-success.js +++ b/ghost/admin/app/components/modal-post-success.js @@ -1,5 +1,6 @@ import Component from '@glimmer/component'; import copyTextToClipboard from 'ghost-admin/utils/copy-text-to-clipboard'; +import {authorNames} from '../helpers/author-names'; import {capitalize} from '@ember/string'; import {inject as service} from '@ember/service'; import {task, timeout} from 'ember-concurrency'; @@ -38,6 +39,10 @@ export default class PostSuccessModal extends Component { return encodeURIComponent(`${this.post.title} ${this.post.url}`); } + get authorNames() { + return authorNames([this.post.authors]); + } + @task *handleCopyLink() { copyTextToClipboard(this.post.url); diff --git a/ghost/admin/app/components/posts-list/list.js b/ghost/admin/app/components/posts-list/list.js index d0ecbb7a42..449e914341 100644 --- a/ghost/admin/app/components/posts-list/list.js +++ b/ghost/admin/app/components/posts-list/list.js @@ -2,13 +2,17 @@ import Component from '@glimmer/component'; import PostSuccessModal from '../modal-post-success'; import {inject as service} from '@ember/service'; import {task} from 'ember-concurrency'; +import {tracked} from '@glimmer/tracking'; export default class PostsList extends Component { @service store; @service modals; @service feature; + @tracked postCount = 0; + latestScheduledPost = null; + latestPublishedPost = null; constructor() { super(...arguments); @@ -25,6 +29,17 @@ export default class PostsList extends Component { }); localStorage.removeItem('ghost-last-scheduled-post'); } + + if (localStorage.getItem('ghost-last-published-post')) { + await this.getlatestPublishedPost.perform(); + await this.getPostCount.perform(); + this.modals.open(PostSuccessModal, { + post: this.latestPublishedPost, + postCount: this.postCount, + showPostCount: true + }); + localStorage.removeItem('ghost-last-published-post'); + } } get list() { @@ -36,4 +51,16 @@ export default class PostsList extends Component { const result = yield this.store.query('post', {filter: `id:${localStorage.getItem('ghost-last-scheduled-post')}`, limit: 1}); this.latestScheduledPost = result.toArray()[0]; } -} + + @task + *getlatestPublishedPost() { + const result = yield this.store.query('post', {filter: `id:${localStorage.getItem('ghost-last-published-post')}`, limit: 1}); + this.latestPublishedPost = result.toArray()[0]; + } + + @task + *getPostCount() { + const result = yield this.store.query('post', {filter: 'status:published', limit: 1, page: 1}); + this.postCount = result.meta.pagination.total; + } +} \ No newline at end of file diff --git a/ghost/admin/app/styles/components/publishmenu.css b/ghost/admin/app/styles/components/publishmenu.css index 6b85d1d167..73a5465c60 100644 --- a/ghost/admin/app/styles/components/publishmenu.css +++ b/ghost/admin/app/styles/components/publishmenu.css @@ -895,10 +895,16 @@ border-radius: var(--radius); } +.modal-post-success .gh-post-card { + border-radius: 8px; + border: 1px solid var(--lightgrey-l1); + box-sizing: border-box; + margin: 24px 0 0 0; +} + .modal-post-success .modal-image { aspect-ratio: 16 / 7.55; overflow: hidden; - margin: calc(var(--padding) * -1) calc(var(--padding) * -1) var(--padding); } .modal-post-success .modal-image img { @@ -906,7 +912,8 @@ width: 100%; height: 100%; object-fit: cover; - border-radius: var(--radius) var(--radius) 0 0; + border-radius: 7px 7px 0 0; + box-sizing: border-box; } .modal-post-success .modal-header { @@ -932,6 +939,48 @@ line-height: 1.4; letter-spacing: -0.01em; text-wrap: pretty; + padding: 16px 24px; +} + +.modal-post-success .modal-body p { + font-size: 1.6rem; + line-height: 1.5em; +} + +.modal-post-success .modal-body p.post-excerpt { + -webkit-line-clamp: 2; + display: -webkit-box; + -webkit-box-orient: vertical; + overflow: hidden; + margin: 0 0 16px 0; +} + +.modal-post-success .email { + font-size: 1.6rem; + padding: 0; +} + +.modal-post-success .modal-body .gh-post-details { + display: flex; + align-items: center; + gap: 4px; + margin-bottom: 16px; + font-size: 1.4rem; +} + +.modal-post-success .modal-body .gh-post-details .gh-post-bookmark-site-name { + font-weight: 600; + flex-shrink: 0; + max-width: 200px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.modal-post-success .modal-body .gh-post-bookmark-site-icon { + width: 24px; + height: 24px; + } .modal-post-success .modal-body strong.nowrap { @@ -939,17 +988,44 @@ } .modal-post-success .modal-footer { + background: var(--whitegrey-l2); + margin-top: 0; + gap: 16px; + padding: 16px 24px; + border-top: 1px solid var(--lightgrey-l1); + border-radius: 0 0 8px 8px; +} + + +.modal-post-success .modal-footer-email { + background: var(--white); + margin-top: 36px; + gap: 16px; + padding: 0; + border: none; + border-radius: 0; + text-align: right; +} + +.modal-post-success .modal-footer .share-buttons { + display: flex; + justify-content: space-evenly; + align-items: center; gap: 16px; - margin-top: var(--padding); } .modal-post-success .modal-footer .gh-btn { - display: flex; - justify-content: center; - align-items: center; min-width: 64px; height: 40px; border-radius: 4px; + display: flex; + justify-content: center; + align-items: center; +} + +.modal-post-success .modal-footer .copy-preview-link { + background: var(--white); + border: 1px solid var(--lightgrey-l1); } .modal-post-success .modal-footer .gh-btn:not(:first-child) { @@ -959,6 +1035,8 @@ .modal-post-success .modal-footer .gh-btn span { padding-inline: 18px; font-size: 1.4rem; + height: 100%; + align-content: center; } .modal-post-success .modal-footer .gh-btn-primary { @@ -971,6 +1049,12 @@ .modal-post-success .modal-footer .gh-btn:is(.twitter, .threads, .facebook, .linkedin) { width: 56px; + background: var(--white); + border: 1px solid var(--lightgrey-l1); +} + +.modal-post-success .modal-footer .gh-btn:is(.twitter, .threads, .facebook, .linkedin, .copy-link, .copy-preview-link):hover { + background: var(--whitegrey-l1); } .modal-post-success .modal-footer .gh-btn:is(.twitter, .threads, .facebook, .linkedin) span { @@ -991,27 +1075,18 @@ right: 24px; } -.modal-post-success:has(.modal-image) .close { - display: flex; - justify-content: center; - align-items: center; - width: 32px; - height: 32px; - top: 16px; - right: 16px; - background-color: rgba(0, 0, 0, 0.4); - border-radius: 50%; -} +@media (max-width: 500px) { + .modal-post-success .modal-header h1 { + font-size: 2.4rem; + } + + .modal-post-success .modal-footer { + display: flex; + flex-direction: column; + } -.modal-post-success:has(.modal-image) .close:hover { - background-color: rgba(0, 0, 0, 0.3); -} - -.modal-post-success:has(.modal-image) .close svg { - width: 14px; - height: 14px; -} - -.modal-post-success:has(.modal-image) .close svg path { - fill: white; -} + .modal-post-success .modal-footer .copy-link, + .modal-post-success .modal-footer .copy-preview-link { + width: 100%!important; + } +} \ No newline at end of file diff --git a/ghost/admin/app/styles/layouts/content.css b/ghost/admin/app/styles/layouts/content.css index 3e69f24a25..7bb9b30b05 100644 --- a/ghost/admin/app/styles/layouts/content.css +++ b/ghost/admin/app/styles/layouts/content.css @@ -725,7 +725,7 @@ .gh-canvas-title.gh-post-title { max-width: 880px; - padding: 20px 0 12px; + padding: 20px 0 0 0; font-size: 3.2rem; line-height: 1.2em; overflow: inherit; @@ -1481,6 +1481,11 @@ transition: all .1s linear; } +.gh-post-list-cta:hover { + border-color: var(--lightgrey-l2); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15); +} + .gh-list-data .gh-post-list-cta { justify-content: center; width: 56px; @@ -1491,6 +1496,10 @@ margin-right: 0; } +.gh-post-analytics-header .share svg { + margin-top: -2px; +} + .gh-post-list-cta.is-hovered { border-color: var(--whitegrey-d2); } diff --git a/ghost/admin/public/assets/icons/link.svg b/ghost/admin/public/assets/icons/link.svg index 3678b1906c..272bbcc3d4 100644 --- a/ghost/admin/public/assets/icons/link.svg +++ b/ghost/admin/public/assets/icons/link.svg @@ -1,4 +1 @@ - - link - - \ No newline at end of file +Hyperlink 3 Streamline Icon: https://streamlinehq.com \ No newline at end of file