From d24a5a06465544fb10c5266124d24958ca0587db Mon Sep 17 00:00:00 2001 From: Sodbileg Gansukh Date: Thu, 1 Aug 2024 17:09:11 +0800 Subject: [PATCH] Started implementing the new publishing flow --- .../editor/modals/publish-flow/confirm.js | 5 + .../app/components/modal-publish-flow.hbs | 155 ++++++++++++++++++ .../app/components/modal-publish-flow.js | 40 +++++ .../admin/app/components/posts/analytics.hbs | 19 ++- ghost/admin/app/components/posts/analytics.js | 47 ++++++ ghost/admin/app/controllers/posts.js | 35 ++++ .../app/styles/components/publishmenu.css | 106 ++++++++++++ ghost/admin/app/templates/posts.hbs | 8 + .../public/assets/icons/social-threads.svg | 10 ++ 9 files changed, 422 insertions(+), 3 deletions(-) create mode 100644 ghost/admin/app/components/modal-publish-flow.hbs create mode 100644 ghost/admin/app/components/modal-publish-flow.js create mode 100644 ghost/admin/public/assets/icons/social-threads.svg 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 54410befbe..aea42ef4e0 100644 --- a/ghost/admin/app/components/editor/modals/publish-flow/confirm.js +++ b/ghost/admin/app/components/editor/modals/publish-flow/confirm.js @@ -91,6 +91,11 @@ export default class PublishFlowOptions extends Component { try { yield this.args.saveTask.perform(); + if (this.args.publishOptions.isScheduled) { + window.location.href = '/ghost/#/posts/?success=true'; + } else { + window.location.href = `/ghost/#/posts/analytics/${this.args.publishOptions.post.id}/?success=true`; + } } catch (e) { if (e === undefined && this.args.publishOptions.post.errors.length !== 0) { // validation error diff --git a/ghost/admin/app/components/modal-publish-flow.hbs b/ghost/admin/app/components/modal-publish-flow.hbs new file mode 100644 index 0000000000..7134e9620c --- /dev/null +++ b/ghost/admin/app/components/modal-publish-flow.hbs @@ -0,0 +1,155 @@ +{{#if this.post.featureImage}} + +{{/if}} + + + +{{!-- disable mouseDown so it doesn't trigger focus-out validations --}} + + {{svg-jar "close"}} + + + + + diff --git a/ghost/admin/app/components/modal-publish-flow.js b/ghost/admin/app/components/modal-publish-flow.js new file mode 100644 index 0000000000..bdd005f0ad --- /dev/null +++ b/ghost/admin/app/components/modal-publish-flow.js @@ -0,0 +1,40 @@ +import ModalComponent from 'ghost-admin/components/modal-base'; +// import copyTextToClipboard from 'ghost-admin/utils/copy-text-to-clipboard'; +import {alias} from '@ember/object/computed'; +// import {inject} from 'ghost-admin/decorators/inject'; +import {inject as service} from '@ember/service'; +// import {task, timeout} from 'ember-concurrency'; + +export default ModalComponent.extend({ + store: service(), + + classNames: 'modal-publish-flow', + + // signinUrl: null, + // config: inject(), + + post: alias('model') + + // didInsertElement() { + // this._super(...arguments); + + // this._signinUrlUpdateTask.perform(); + // }, + + // actions: { + // // noop - we don't want the enter key doing anything + // confirm() {} + // }, + + // copySigninUrl: task(function* () { + // copyTextToClipboard(this.signinUrl); + // yield timeout(1000); + // return true; + // }), + + // _signinUrlUpdateTask: task(function*() { + // const memberSigninURL = yield this.member.fetchSigninUrl.perform(); + + // this.set('signinUrl', memberSigninURL.url); + // }).drop() +}); diff --git a/ghost/admin/app/components/posts/analytics.hbs b/ghost/admin/app/components/posts/analytics.hbs index c08e6aeb71..f18df2b59b 100644 --- a/ghost/admin/app/components/posts/analytics.hbs +++ b/ghost/admin/app/components/posts/analytics.hbs @@ -34,9 +34,13 @@ {{moment-format publishedAt "HH:mm"}} {{/let}} - - {{svg-jar "pen" title=""}}Edit post - +
+ + + + {{svg-jar "pen" title=""}}Edit post + +
@@ -202,3 +206,12 @@ {{/if}} + +{{#if this.showPublishFlowModal}} + +{{/if}} \ No newline at end of file diff --git a/ghost/admin/app/components/posts/analytics.js b/ghost/admin/app/components/posts/analytics.js index 0f81f7454d..5ab986ddbd 100644 --- a/ghost/admin/app/components/posts/analytics.js +++ b/ghost/admin/app/components/posts/analytics.js @@ -1,8 +1,10 @@ import Component from '@glimmer/component'; +import PublishOptionsResource from 'ghost-admin/helpers/publish-options'; import {action} from '@ember/object'; import {didCancel, task} from 'ember-concurrency'; import {inject as service} from '@ember/service'; import {tracked} from '@glimmer/tracking'; +import {use} from 'ember-could-get-used-to-this'; /** * @typedef {import('../../services/dashboard-stats').SourceAttributionCount} SourceAttributionCount @@ -24,6 +26,7 @@ export default class Analytics extends Component { @service utils; @service feature; @service store; + @service router; @tracked sources = null; @tracked links = null; @@ -31,8 +34,25 @@ export default class Analytics extends Component { @tracked sortColumn = 'signups'; @tracked showSuccess; @tracked updateLinkId; + @tracked showPublishFlowModal = false; displayOptions = DISPLAY_OPTIONS; + @use publishOptions = new PublishOptionsResource(() => [this.args.post]); + + constructor() { + super(...arguments); + this.checkUrlParameter(); + } + + checkUrlParameter() { + const currentURL = this.router.currentURL; + const url = new URL(window.location.origin + currentURL); + const successParam = url.searchParams.get('success'); + if (successParam === 'true') { + this.showPublishFlowModal = true; + } + } + get post() { return this.args.post; } @@ -142,6 +162,33 @@ export default class Analytics extends Component { } } + @action + togglePublishFlowModal() { + if (this.showPublishFlowModal) { + const hash = window.location.hash; + + // Extract the part before '?' and the query parameters + const [path, queryParamsString] = hash.split('?'); + + // If there are query parameters, proceed to modify them + if (queryParamsString) { + const searchParams = new URLSearchParams(queryParamsString); + + // Remove the 'success' parameter + searchParams.delete('success'); + + // Construct the new hash fragment + const newQueryParamsString = searchParams.toString(); + const newHash = newQueryParamsString ? `${path}?${newQueryParamsString}` : path; + + // Update the URL without reloading the page + window.history.replaceState(null, '', `${window.location.pathname}${window.location.search}${newHash}`); + } + } + + this.showPublishFlowModal = !this.showPublishFlowModal; + } + updateLinkData(linksData) { let updatedLinks; if (this.links?.length) { diff --git a/ghost/admin/app/controllers/posts.js b/ghost/admin/app/controllers/posts.js index 014cad0f47..b9b69a78f0 100644 --- a/ghost/admin/app/controllers/posts.js +++ b/ghost/admin/app/controllers/posts.js @@ -4,6 +4,7 @@ import {DEFAULT_QUERY_PARAMS} from 'ghost-admin/helpers/reset-query-params'; import {action} from '@ember/object'; import {inject} from 'ghost-admin/decorators/inject'; import {inject as service} from '@ember/service'; +import {task} from 'ember-concurrency'; import {tracked} from '@glimmer/tracking'; const TYPES = [{ @@ -68,6 +69,8 @@ export default class PostsController extends Controller { @tracked tag = null; @tracked order = null; @tracked selectionList = new SelectionList(this.postsInfinityModel); + @tracked showPublishFlowModal = false; + @tracked latestScheduledPost = null; availableTypes = TYPES; availableVisibilities = VISIBILITIES; @@ -81,10 +84,31 @@ export default class PostsController extends Controller { constructor() { super(...arguments); + this.checkUrlParameter(); + + this.router.on('routeDidChange', () => { + this.checkUrlParameter(); + }); + + this.getLatestScheduledPost.perform(); Object.assign(this, DEFAULT_QUERY_PARAMS.posts); } + checkUrlParameter() { + const hash = window.location.hash; // Get the full hash fragment + const queryParamsString = hash.split('?')[1]; // Get the part after '?' + + if (queryParamsString) { + const searchParams = new URLSearchParams(queryParamsString); + const successParam = searchParams.get('success'); + + if (successParam === 'true') { + this.showPublishFlowModal = true; + } + } + } + get postsInfinityModel() { return this.model; } @@ -174,4 +198,15 @@ export default class PostsController extends Controller { openEditor(post) { this.router.transitionTo('lexical-editor.edit', 'post', post.id); } + + @action + togglePublishFlowModal() { + this.showPublishFlowModal = !this.showPublishFlowModal; + } + + @task + *getLatestScheduledPost() { + const result = yield this.store.query('post', {filter: 'status:scheduled', limit: 1}); + this.latestScheduledPost = result.toArray()[0]; + } } diff --git a/ghost/admin/app/styles/components/publishmenu.css b/ghost/admin/app/styles/components/publishmenu.css index 6a781a9d63..63644d92a6 100644 --- a/ghost/admin/app/styles/components/publishmenu.css +++ b/ghost/admin/app/styles/components/publishmenu.css @@ -880,3 +880,109 @@ height: 20px; margin-right: 6px; } + +/* Publish flow modal +/* ---------------------------------------------------------- */ + +.modal-publish-flow { + overflow: hidden; +} + +.modal-publish-flow .modal-image { + aspect-ratio: 16 / 7.55; + overflow: hidden; + margin: -32px -32px 32px; +} + +.modal-publish-flow .modal-image img { + display: block; + width: 100%; + height: 100%; + object-fit: cover; +} + +.modal-publish-flow .modal-header { + margin: 0; +} + +.modal-publish-flow .modal-header h1 { + display: flex; + flex-direction: column; + margin: 0; + font-size: 3.2rem; + font-weight: 700; +} + +.modal-publish-flow .modal-header h1 span:has(+ span) { + color: var(--green); +} + +.modal-publish-flow .modal-body { + margin-top: 16px; + font-size: 1.8rem; + line-height: 1.4; + letter-spacing: -0.005em; +} + +.modal-publish-flow .modal-footer .gh-btn { + height: 48px; + min-width: auto; +} + +.modal-publish-flow .modal-footer .gh-btn span { + padding-inline: 16px; + font-size: 1.5rem; +} + +.modal-publish-flow .modal-footer:has(.twitter) .gh-btn-primary { + flex-grow: 1; +} + +.modal-publish-flow .modal-footer .gh-btn:is(.twitter, .threads, .facebook, .linkedin) { + width: 56px; +} + +.modal-publish-flow .modal-footer .gh-btn:is(.twitter, .threads, .facebook, .linkedin) span { + font-size: 0; +} + +.modal-publish-flow .modal-footer .gh-btn svg { + width: 16px; + height: 16px; +} + +.modal-publish-flow .modal-footer .gh-btn.twitter svg path { + fill: black; +} + +.modal-publish-flow .modal-footer .gh-btn-primary svg { + position: relative; + top: -1px; +} + +.modal-publish-flow .modal-footer .gh-btn-primary svg path { + fill: white +} + +.modal-publish-flow:has(.modal-image) .close { + display: flex; + justify-content: center; + align-items: center; + width: 32px; + height: 32px; + background-color: rgba(0, 0, 0, 0.2); + border-radius: 50%; +} + +.modal-publish-flow:has(.modal-image) .close:hover { + background-color: rgba(0, 0, 0, 0.25); +} + +.modal-publish-flow:has(.modal-image) .close svg { + width: 14px; + height: 14px; +} + +.modal-publish-flow:has(.modal-image) .close svg path { + fill: white; +} diff --git a/ghost/admin/app/templates/posts.hbs b/ghost/admin/app/templates/posts.hbs index f0d0b6bbe8..726a2c5c40 100644 --- a/ghost/admin/app/templates/posts.hbs +++ b/ghost/admin/app/templates/posts.hbs @@ -59,3 +59,11 @@ {{outlet}} + +{{#if this.showPublishFlowModal}} + +{{/if}} \ No newline at end of file diff --git a/ghost/admin/public/assets/icons/social-threads.svg b/ghost/admin/public/assets/icons/social-threads.svg new file mode 100644 index 0000000000..dc95af6271 --- /dev/null +++ b/ghost/admin/public/assets/icons/social-threads.svg @@ -0,0 +1,10 @@ + + + + + + + + + +