├── .csscomb.json
├── .editorconfig
├── .ember-cli
├── .eslintignore
├── .eslintrc.js
├── .github
├── CONTRIBUTING.md
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ └── test.yml
├── .gitignore
├── .lint-todo
├── .lint-todorc.js
├── .template-lintrc.js
├── .watchmanconfig
├── Gruntfile.js
├── LICENSE
├── README.md
├── SECURITY.md
├── app
├── README.md
├── adapters
│ ├── api-key.js
│ ├── application.js
│ ├── base.js
│ ├── custom-theme-setting-list.js
│ ├── email.js
│ ├── embedded-relation-adapter.js
│ ├── label.js
│ ├── member.js
│ ├── newsletter.js
│ ├── offer.js
│ ├── page.js
│ ├── post.js
│ ├── setting.js
│ ├── tag.js
│ ├── theme.js
│ ├── tier.js
│ └── user.js
├── app.js
├── authenticators
│ └── cookie.js
├── components
│ ├── aspect-ratio-box.hbs
│ ├── aspect-ratio-box.js
│ ├── custom-theme-settings
│ │ ├── boolean.hbs
│ │ ├── boolean.js
│ │ ├── color.hbs
│ │ ├── color.js
│ │ ├── image.hbs
│ │ ├── image.js
│ │ ├── select.hbs
│ │ ├── select.js
│ │ ├── text.hbs
│ │ └── text.js
│ ├── dashboard
│ │ ├── charts
│ │ │ ├── anchor.hbs
│ │ │ ├── anchor.js
│ │ │ ├── engagement.hbs
│ │ │ ├── engagement.js
│ │ │ ├── overview.hbs
│ │ │ ├── overview.js
│ │ │ ├── paid-breakdown.hbs
│ │ │ ├── paid-breakdown.js
│ │ │ ├── paid-mix.hbs
│ │ │ ├── paid-mix.js
│ │ │ ├── paid-mrr.hbs
│ │ │ ├── paid-mrr.js
│ │ │ ├── recents.hbs
│ │ │ └── recents.js
│ │ ├── parts
│ │ │ ├── metric.hbs
│ │ │ ├── percentage.hbs
│ │ │ └── zero.hbs
│ │ ├── prototype
│ │ │ ├── control-panel.hbs
│ │ │ └── control-panel.js
│ │ └── resources
│ │ │ ├── community.hbs
│ │ │ ├── newsletter.hbs
│ │ │ ├── newsletter.js
│ │ │ ├── resources.hbs
│ │ │ ├── resources.js
│ │ │ ├── staff-picks.hbs
│ │ │ ├── staff-picks.js
│ │ │ ├── whats-new.hbs
│ │ │ └── whats-new.js
│ ├── editor
│ │ ├── modals
│ │ │ ├── preview.hbs
│ │ │ ├── preview.js
│ │ │ ├── preview
│ │ │ │ ├── browser.hbs
│ │ │ │ ├── browser.js
│ │ │ │ ├── email.hbs
│ │ │ │ ├── email.js
│ │ │ │ ├── mobile.hbs
│ │ │ │ ├── mobile.js
│ │ │ │ ├── social.hbs
│ │ │ │ └── social.js
│ │ │ ├── publish-flow.hbs
│ │ │ ├── publish-flow.js
│ │ │ ├── publish-flow
│ │ │ │ ├── complete-with-email-error.hbs
│ │ │ │ ├── complete-with-email-error.js
│ │ │ │ ├── complete.hbs
│ │ │ │ ├── confirm.hbs
│ │ │ │ ├── confirm.js
│ │ │ │ ├── options.hbs
│ │ │ │ └── options.js
│ │ │ ├── update-flow.hbs
│ │ │ └── update-flow.js
│ │ ├── publish-buttons.hbs
│ │ ├── publish-management.hbs
│ │ ├── publish-management.js
│ │ └── publish-options
│ │ │ ├── email-recipients.hbs
│ │ │ ├── publish-at.hbs
│ │ │ ├── publish-at.js
│ │ │ ├── publish-type.hbs
│ │ │ └── publish-type.js
│ ├── epm-modal-container.hbs
│ ├── epm-modal-container.js
│ ├── gh-alert.hbs
│ ├── gh-alert.js
│ ├── gh-alerts.hbs
│ ├── gh-alerts.js
│ ├── gh-app.hbs
│ ├── gh-basic-dropdown.hbs
│ ├── gh-basic-dropdown.js
│ ├── gh-benefit-item.hbs
│ ├── gh-benefit-item.js
│ ├── gh-billing-iframe.hbs
│ ├── gh-billing-iframe.js
│ ├── gh-billing-modal.hbs
│ ├── gh-billing-modal.js
│ ├── gh-billing-update-button.hbs
│ ├── gh-billing-update-button.js
│ ├── gh-blog-url.hbs
│ ├── gh-blog-url.js
│ ├── gh-brand-settings-form.hbs
│ ├── gh-brand-settings-form.js
│ ├── gh-browser-preview.hbs
│ ├── gh-browser-preview.js
│ ├── gh-canvas-header.hbs
│ ├── gh-canvas-header.js
│ ├── gh-cm-editor.hbs
│ ├── gh-cm-editor.js
│ ├── gh-content-cover.js
│ ├── gh-contentfilter.hbs
│ ├── gh-contentfilter.js
│ ├── gh-custom-view-title.hbs
│ ├── gh-custom-view-title.js
│ ├── gh-date-picker.hbs
│ ├── gh-date-picker.js
│ ├── gh-date-time-picker.hbs
│ ├── gh-date-time-picker.js
│ ├── gh-dropdown-button.js
│ ├── gh-dropdown.js
│ ├── gh-editor-feature-image.hbs
│ ├── gh-editor-feature-image.js
│ ├── gh-editor-post-status.hbs
│ ├── gh-editor-post-status.js
│ ├── gh-editor.hbs
│ ├── gh-editor.js
│ ├── gh-email-preview-link.hbs
│ ├── gh-email-preview-link.js
│ ├── gh-error-message.hbs
│ ├── gh-error-message.js
│ ├── gh-feature-flag.hbs
│ ├── gh-feature-flag.js
│ ├── gh-file-input.js
│ ├── gh-file-upload.hbs
│ ├── gh-file-upload.js
│ ├── gh-file-uploader.hbs
│ ├── gh-file-uploader.js
│ ├── gh-font-selector.hbs
│ ├── gh-font-selector.js
│ ├── gh-form-group.js
│ ├── gh-fullscreen-modal.hbs
│ ├── gh-fullscreen-modal.js
│ ├── gh-html-iframe.hbs
│ ├── gh-html-iframe.js
│ ├── gh-image-uploader-with-preview.hbs
│ ├── gh-image-uploader.hbs
│ ├── gh-image-uploader.js
│ ├── gh-infinity-loader.hbs
│ ├── gh-infinity-loader.js
│ ├── gh-input-with-select
│ │ ├── index.hbs
│ │ ├── index.js
│ │ ├── suggested-option.hbs
│ │ ├── trigger.hbs
│ │ └── trigger.js
│ ├── gh-koenig-editor-react.hbs
│ ├── gh-koenig-editor-react.js
│ ├── gh-koenig-editor.hbs
│ ├── gh-koenig-editor.js
│ ├── gh-launch-wizard
│ │ ├── connect-stripe.hbs
│ │ ├── connect-stripe.js
│ │ ├── customise-design.hbs
│ │ ├── customise-design.js
│ │ ├── finalise.hbs
│ │ ├── finalise.js
│ │ ├── set-pricing.hbs
│ │ └── set-pricing.js
│ ├── gh-link-to-custom-views-index.hbs
│ ├── gh-link-to-custom-views-index.js
│ ├── gh-loading-list.hbs
│ ├── gh-loading-spinner.hbs
│ ├── gh-loading-spinner.js
│ ├── gh-markdown-editor.hbs
│ ├── gh-markdown-editor.js
│ ├── gh-member-avatar.hbs
│ ├── gh-member-avatar.js
│ ├── gh-member-details-activity.hbs
│ ├── gh-member-details.hbs
│ ├── gh-member-details.js
│ ├── gh-member-label-input.hbs
│ ├── gh-member-label-input.js
│ ├── gh-member-settings-form.hbs
│ ├── gh-member-settings-form.js
│ ├── gh-member-single-label-input.hbs
│ ├── gh-member-single-label-input.js
│ ├── gh-members-filter-count.hbs
│ ├── gh-members-filter-count.js
│ ├── gh-members-import-mapping-input.hbs
│ ├── gh-members-import-mapping-input.js
│ ├── gh-members-import-table.hbs
│ ├── gh-members-import-table.js
│ ├── gh-members-list-item-column.hbs
│ ├── gh-members-list-item-column.js
│ ├── gh-members-list-item.hbs
│ ├── gh-members-list-item.js
│ ├── gh-members-no-members.hbs
│ ├── gh-members-no-members.js
│ ├── gh-members-payments-setting.hbs
│ ├── gh-members-payments-setting.js
│ ├── gh-members-recipient-select.hbs
│ ├── gh-members-recipient-select.js
│ ├── gh-members-segment-count.hbs
│ ├── gh-members-segment-count.js
│ ├── gh-members-segment-select.hbs
│ ├── gh-members-segment-select.js
│ ├── gh-membership-tiers-alpha.hbs
│ ├── gh-membership-tiers-alpha.js
│ ├── gh-mobile-nav-bar.hbs
│ ├── gh-mobile-nav-bar.js
│ ├── gh-nav-menu.hbs
│ ├── gh-nav-menu.js
│ ├── gh-nav-menu
│ │ ├── design.hbs
│ │ ├── design.js
│ │ ├── footer.hbs
│ │ ├── footer.js
│ │ ├── main.hbs
│ │ └── main.js
│ ├── gh-navitem-url-input.js
│ ├── gh-navitem.hbs
│ ├── gh-navitem.js
│ ├── gh-notification.hbs
│ ├── gh-notification.js
│ ├── gh-notifications.hbs
│ ├── gh-notifications.js
│ ├── gh-portal-links.hbs
│ ├── gh-portal-links.js
│ ├── gh-post-bookmark.hbs
│ ├── gh-post-settings-menu.hbs
│ ├── gh-post-settings-menu.js
│ ├── gh-post-settings-menu
│ │ ├── email.hbs
│ │ ├── email.js
│ │ ├── visibility-segment-select.hbs
│ │ └── visibility-segment-select.js
│ ├── gh-posts-list-item.hbs
│ ├── gh-posts-list-item.js
│ ├── gh-power-select
│ │ ├── trigger.hbs
│ │ └── trigger.js
│ ├── gh-progress-bar.hbs
│ ├── gh-progress-bar.js
│ ├── gh-psm-authors-input.hbs
│ ├── gh-psm-authors-input.js
│ ├── gh-psm-tags-input.hbs
│ ├── gh-psm-tags-input.js
│ ├── gh-psm-template-select.hbs
│ ├── gh-psm-template-select.js
│ ├── gh-psm-visibility-input.hbs
│ ├── gh-psm-visibility-input.js
│ ├── gh-recipient-filter-count.hbs
│ ├── gh-role-selection.hbs
│ ├── gh-role-selection.js
│ ├── gh-scroll-trigger.hbs
│ ├── gh-scroll-trigger.js
│ ├── gh-search-input.hbs
│ ├── gh-search-input.js
│ ├── gh-simplemde.hbs
│ ├── gh-simplemde.js
│ ├── gh-site-iframe.hbs
│ ├── gh-site-iframe.js
│ ├── gh-skip-link.js
│ ├── gh-tag-settings-form.hbs
│ ├── gh-tag-settings-form.js
│ ├── gh-tags-list-item.hbs
│ ├── gh-task-button.hbs
│ ├── gh-task-button.js
│ ├── gh-text-input.hbs
│ ├── gh-text-input.js
│ ├── gh-textarea.js
│ ├── gh-theme-error-li.hbs
│ ├── gh-theme-error-li.js
│ ├── gh-theme-table.hbs
│ ├── gh-theme-table.js
│ ├── gh-tier-card.hbs
│ ├── gh-tier-card.js
│ ├── gh-tiers-price-billingperiod.hbs
│ ├── gh-tiers-price-billingperiod.js
│ ├── gh-timezone-select.hbs
│ ├── gh-timezone-select.js
│ ├── gh-token-input.hbs
│ ├── gh-token-input.js
│ ├── gh-token-input
│ │ ├── label-selected-item.hbs
│ │ ├── label-token.hbs
│ │ ├── label-token.js
│ │ ├── select-multiple.hbs
│ │ ├── select-multiple.js
│ │ ├── suggested-option.hbs
│ │ ├── tag-token.hbs
│ │ ├── tag-token.js
│ │ ├── trigger.hbs
│ │ └── trigger.js
│ ├── gh-trim-focus-input.js
│ ├── gh-unsplash-photo.hbs
│ ├── gh-unsplash-photo.js
│ ├── gh-unsplash.hbs
│ ├── gh-unsplash.js
│ ├── gh-uploader.hbs
│ ├── gh-uploader.js
│ ├── gh-url-input.hbs
│ ├── gh-url-input.js
│ ├── gh-url-preview.hbs
│ ├── gh-url-preview.js
│ ├── gh-user-active.hbs
│ ├── gh-user-active.js
│ ├── gh-user-invited.hbs
│ ├── gh-user-invited.js
│ ├── gh-user-list-item.hbs
│ ├── gh-user-list-item.js
│ ├── gh-validation-status-container.js
│ ├── gh-view-title.hbs
│ ├── gh-view-title.js
│ ├── inputs
│ │ ├── select.hbs
│ │ └── select
│ │ │ └── option.hbs
│ ├── koenig-react-editor.hbs
│ ├── koenig-react-editor.js
│ ├── liquid-container.js
│ ├── member
│ │ ├── activity-feed-empty.hbs
│ │ ├── activity-feed.hbs
│ │ ├── newsletter-preference.hbs
│ │ └── newsletter-preference.js
│ ├── members-activity
│ │ ├── event-type-filter.hbs
│ │ ├── event-type-filter.js
│ │ ├── member-filter-trigger.hbs
│ │ ├── member-filter.hbs
│ │ ├── member-filter.js
│ │ ├── no-events.hbs
│ │ ├── table-row.hbs
│ │ └── table.hbs
│ ├── members
│ │ ├── filter-value.hbs
│ │ ├── filter-value.js
│ │ ├── filter.hbs
│ │ └── filter.js
│ ├── modal-base.js
│ ├── modal-delete-all.hbs
│ ├── modal-delete-all.js
│ ├── modal-delete-integration.hbs
│ ├── modal-delete-integration.js
│ ├── modal-delete-member.hbs
│ ├── modal-delete-member.js
│ ├── modal-delete-snippet.hbs
│ ├── modal-delete-snippet.js
│ ├── modal-delete-tag.hbs
│ ├── modal-delete-tag.js
│ ├── modal-delete-user.hbs
│ ├── modal-delete-user.js
│ ├── modal-delete-webhook.hbs
│ ├── modal-delete-webhook.js
│ ├── modal-disconnect-stripe.hbs
│ ├── modal-disconnect-stripe.js
│ ├── modal-early-access.hbs
│ ├── modal-early-access.js
│ ├── modal-email-design-settings.hbs
│ ├── modal-email-design-settings.js
│ ├── modal-free-membership-settings.hbs
│ ├── modal-free-membership-settings.js
│ ├── modal-impersonate-member.hbs
│ ├── modal-impersonate-member.js
│ ├── modal-import-members.hbs
│ ├── modal-import-members.js
│ ├── modal-import-members
│ │ ├── csv-file-mapping.hbs
│ │ ├── csv-file-mapping.js
│ │ ├── csv-file-select.hbs
│ │ └── csv-file-select.js
│ ├── modal-invite-new-user.hbs
│ ├── modal-invite-new-user.js
│ ├── modal-leave-settings.hbs
│ ├── modal-leave-settings.js
│ ├── modal-markdown-help.hbs
│ ├── modal-markdown-help.js
│ ├── modal-member-tier.hbs
│ ├── modal-member-tier.js
│ ├── modal-members-label-form.hbs
│ ├── modal-members-label-form.js
│ ├── modal-portal-settings.hbs
│ ├── modal-portal-settings.js
│ ├── modal-re-authenticate.hbs
│ ├── modal-re-authenticate.js
│ ├── modal-regenerate-key.hbs
│ ├── modal-regenerate-key.js
│ ├── modal-regenerate-token.hbs
│ ├── modal-regenerate-token.js
│ ├── modal-reset-all-passwords.hbs
│ ├── modal-reset-all-passwords.js
│ ├── modal-select-user-role.hbs
│ ├── modal-select-user-role.js
│ ├── modal-stripe-connect.hbs
│ ├── modal-stripe-connect.js
│ ├── modal-suspend-user.hbs
│ ├── modal-suspend-user.js
│ ├── modal-tier.hbs
│ ├── modal-tier.js
│ ├── modal-transfer-owner.hbs
│ ├── modal-transfer-owner.js
│ ├── modal-unsubscribe-members.hbs
│ ├── modal-unsubscribe-members.js
│ ├── modal-unsuspend-user.hbs
│ ├── modal-unsuspend-user.js
│ ├── modal-update-snippet.hbs
│ ├── modal-update-snippet.js
│ ├── modal-upgrade-host-limit.hbs
│ ├── modal-upgrade-host-limit.js
│ ├── modal-upgrade-unsuspend-user-host-limit.hbs
│ ├── modal-upgrade-unsuspend-user-host-limit.js
│ ├── modal-upload-image.hbs
│ ├── modal-upload-image.js
│ ├── modal-webhook-form.hbs
│ ├── modal-webhook-form.js
│ ├── modal-whats-new.js
│ ├── modals
│ │ ├── confirm-unsaved-changes.hbs
│ │ ├── custom-view-form.hbs
│ │ ├── custom-view-form.js
│ │ ├── delete-post.hbs
│ │ ├── delete-post.js
│ │ ├── design
│ │ │ ├── confirm-delete-theme.hbs
│ │ │ ├── confirm-delete-theme.js
│ │ │ ├── install-theme.hbs
│ │ │ ├── install-theme.js
│ │ │ ├── theme-errors.hbs
│ │ │ ├── upload-theme.hbs
│ │ │ ├── upload-theme.js
│ │ │ ├── view-theme.hbs
│ │ │ └── view-theme.js
│ │ ├── editor
│ │ │ └── confirm-leave.hbs
│ │ ├── email-preview.hbs
│ │ ├── email-preview.js
│ │ ├── limits
│ │ │ ├── custom-integration.hbs
│ │ │ ├── custom-theme.hbs
│ │ │ └── multiple-newsletters.hbs
│ │ ├── members
│ │ │ ├── bulk-add-label.hbs
│ │ │ ├── bulk-add-label.js
│ │ │ ├── bulk-delete.hbs
│ │ │ ├── bulk-delete.js
│ │ │ ├── bulk-remove-label.hbs
│ │ │ ├── bulk-remove-label.js
│ │ │ ├── bulk-unsubscribe.hbs
│ │ │ └── bulk-unsubscribe.js
│ │ ├── new-custom-integration.hbs
│ │ ├── new-custom-integration.js
│ │ ├── newsletters
│ │ │ ├── confirm-archive.hbs
│ │ │ ├── confirm-newsletter-email.hbs
│ │ │ ├── confirm-unarchive.hbs
│ │ │ ├── edit.hbs
│ │ │ ├── edit.js
│ │ │ ├── edit
│ │ │ │ ├── design.hbs
│ │ │ │ ├── design.js
│ │ │ │ ├── preview.hbs
│ │ │ │ ├── preview.js
│ │ │ │ ├── settings.hbs
│ │ │ │ └── settings.js
│ │ │ ├── new.hbs
│ │ │ ├── new.js
│ │ │ ├── verify-newsletter-email.hbs
│ │ │ └── verify-newsletter-email.js
│ │ ├── offers
│ │ │ ├── archive.hbs
│ │ │ ├── archive.js
│ │ │ ├── link.hbs
│ │ │ ├── link.js
│ │ │ ├── unarchive.hbs
│ │ │ └── unarchive.js
│ │ ├── search.hbs
│ │ ├── search.js
│ │ ├── settings
│ │ │ ├── confirm-email.hbs
│ │ │ ├── verify-email.hbs
│ │ │ └── verify-email.js
│ │ └── tiers
│ │ │ ├── archive.hbs
│ │ │ ├── archive.js
│ │ │ ├── unarchive.hbs
│ │ │ └── unarchive.js
│ ├── power-select-vertical-collection-options.hbs
│ ├── power-select-vertical-collection-options.js
│ ├── react-component.hbs
│ ├── settings
│ │ ├── design
│ │ │ ├── general-settings-form.hbs
│ │ │ └── theme-settings-form.hbs
│ │ ├── form-fields
│ │ │ ├── accent-color.hbs
│ │ │ ├── accent-color.js
│ │ │ ├── publication-cover.hbs
│ │ │ ├── publication-cover.js
│ │ │ ├── publication-icon.hbs
│ │ │ ├── publication-icon.js
│ │ │ ├── publication-logo.hbs
│ │ │ ├── publication-logo.js
│ │ │ ├── site-description.hbs
│ │ │ └── site-description.js
│ │ ├── members-comment-access.hbs
│ │ ├── members-comment-access.js
│ │ ├── members-default-post-access.hbs
│ │ ├── members-default-post-access.js
│ │ ├── members-email
│ │ │ ├── default-recipients-select.hbs
│ │ │ └── default-recipients-select.js
│ │ ├── members-subscription-access.hbs
│ │ ├── members-subscription-access.js
│ │ ├── members
│ │ │ ├── archive-tier.hbs
│ │ │ └── archive-tier.js
│ │ ├── newsletters.hbs
│ │ ├── newsletters.js
│ │ └── newsletters
│ │ │ ├── newsletter-management.hbs
│ │ │ └── newsletter-management.js
│ └── tiers
│ │ ├── segment-select.hbs
│ │ └── segment-select.js
├── controllers
│ ├── application.js
│ ├── billing.js
│ ├── dashboard.js
│ ├── designsandbox.js
│ ├── editor.js
│ ├── editor
│ │ └── edit-loading.js
│ ├── error.js
│ ├── explore.js
│ ├── home.js
│ ├── launch.js
│ ├── member.js
│ ├── members-activity.js
│ ├── members.js
│ ├── members
│ │ └── import.js
│ ├── offer.js
│ ├── offers.js
│ ├── pages-loading.js
│ ├── pages.js
│ ├── posts-loading.js
│ ├── posts.js
│ ├── react-editor.js
│ ├── react-editor
│ │ └── edit-loading.js
│ ├── reset.js
│ ├── settings.js
│ ├── settings
│ │ ├── code-injection.js
│ │ ├── design.js
│ │ ├── design
│ │ │ ├── change-theme.js
│ │ │ ├── change-theme
│ │ │ │ └── install.js
│ │ │ └── index.js
│ │ ├── general.js
│ │ ├── integration.js
│ │ ├── integration
│ │ │ └── webhooks
│ │ │ │ ├── edit.js
│ │ │ │ └── new.js
│ │ ├── integrations.js
│ │ ├── integrations
│ │ │ ├── amp.js
│ │ │ ├── firstpromoter.js
│ │ │ ├── slack.js
│ │ │ ├── unsplash.js
│ │ │ └── zapier.js
│ │ ├── labs.js
│ │ ├── membership.js
│ │ ├── navigation.js
│ │ ├── newsletters.js
│ │ ├── staff
│ │ │ ├── index.js
│ │ │ ├── user-loading.js
│ │ │ └── user.js
│ │ ├── tier.js
│ │ └── tiers.js
│ ├── setup.js
│ ├── setup
│ │ └── done.js
│ ├── signin.js
│ ├── signup.js
│ ├── site.js
│ ├── tag.js
│ ├── tags.js
│ └── whatsnew.js
├── errors
│ ├── email-failed-error.js
│ └── member-import-error.js
├── helpers
│ ├── accent-color-background.js
│ ├── author-names.js
│ ├── background-image-style.js
│ ├── capitalize-first-letter.js
│ ├── currency-symbol.js
│ ├── enable-developer-experiments.js
│ ├── event-name.js
│ ├── feature.js
│ ├── first-name.js
│ ├── format-number.js
│ ├── full-email-address.js
│ ├── get-setting.js
│ ├── gh-count-characters.js
│ ├── gh-count-down-characters.js
│ ├── gh-format-post-time.js
│ ├── gh-pluralize.js
│ ├── gh-price-amount.js
│ ├── gh-user-can-admin.js
│ ├── hex-adjust.js
│ ├── hex-contrast.js
│ ├── highlighted-text.js
│ ├── humanize-setting-key.js
│ ├── integration-icon-style.js
│ ├── is-moment-today.js
│ ├── members-count-fetcher.js
│ ├── members-event-fetcher.js
│ ├── members-event-filter.js
│ ├── moment-site-tz.js
│ ├── most-recently-updated.js
│ ├── noop.js
│ ├── parse-member-event.js
│ ├── post-author-names.js
│ ├── publish-options.js
│ ├── query-selector.js
│ ├── reset-query-params.js
│ ├── set-has.js
│ ├── set-query-params.js
│ ├── site-icon-style.js
│ ├── toggle-feature.js
│ ├── ui-btn-span.js
│ ├── ui-btn.js
│ └── ui-text.js
├── index.html
├── initializers
│ ├── ember-simple-auth.js
│ ├── trailing-hash.js
│ └── upgrade-status.js
├── mixins
│ ├── body-event-listener.js
│ ├── dropdown-mixin.js
│ ├── shortcuts-route.js
│ ├── shortcuts.js
│ ├── text-input.js
│ ├── validation-engine.js
│ └── validation-state.js
├── models
│ ├── action.js
│ ├── api-key.js
│ ├── base.js
│ ├── custom-theme-setting-list.js
│ ├── custom-theme-setting.js
│ ├── email.js
│ ├── integration.js
│ ├── invite.js
│ ├── label.js
│ ├── member-subscription.js
│ ├── member-tier.js
│ ├── member.js
│ ├── navigation-item.js
│ ├── newsletter.js
│ ├── notification.js
│ ├── offer.js
│ ├── page.js
│ ├── post.js
│ ├── role.js
│ ├── setting.js
│ ├── snippet.js
│ ├── tag.js
│ ├── theme.js
│ ├── tier-benefit-item.js
│ ├── tier.js
│ ├── user.js
│ └── webhook.js
├── modifiers
│ ├── autofocus.js
│ ├── movable.js
│ ├── on-resize.js
│ ├── on-scroll.js
│ ├── ratio-zoom.js
│ ├── react-render.js
│ ├── scroll-into-view.js
│ ├── scroll-to.js
│ └── scroll-top.js
├── router.js
├── routes
│ ├── admin.js
│ ├── application.js
│ ├── authenticated.js
│ ├── dashboard.js
│ ├── designsandbox.js
│ ├── editor.js
│ ├── editor
│ │ ├── edit.js
│ │ ├── index.js
│ │ └── new.js
│ ├── error404.js
│ ├── explore.js
│ ├── home.js
│ ├── launch.js
│ ├── member.js
│ ├── member
│ │ └── new.js
│ ├── members-activity.js
│ ├── members.js
│ ├── members
│ │ └── import.js
│ ├── offer.js
│ ├── offer
│ │ └── new.js
│ ├── offers.js
│ ├── pages.js
│ ├── posts.js
│ ├── pro.js
│ ├── react-editor.js
│ ├── react-editor
│ │ ├── edit.js
│ │ ├── index.js
│ │ └── new.js
│ ├── reset.js
│ ├── settings.js
│ ├── settings
│ │ ├── code-injection.js
│ │ ├── design.js
│ │ ├── design
│ │ │ ├── change-theme.js
│ │ │ ├── change-theme
│ │ │ │ ├── install.js
│ │ │ │ └── view.js
│ │ │ └── index.js
│ │ ├── general.js
│ │ ├── integration.js
│ │ ├── integration
│ │ │ └── webhooks
│ │ │ │ ├── edit.js
│ │ │ │ └── new.js
│ │ ├── integrations.js
│ │ ├── integrations
│ │ │ ├── amp.js
│ │ │ ├── firstpromoter.js
│ │ │ ├── new.js
│ │ │ ├── slack.js
│ │ │ ├── unsplash.js
│ │ │ └── zapier.js
│ │ ├── labs.js
│ │ ├── members-email.js
│ │ ├── membership.js
│ │ ├── navigation.js
│ │ ├── newsletters.js
│ │ ├── newsletters
│ │ │ ├── edit-newsletter.js
│ │ │ └── new-newsletter.js
│ │ ├── staff
│ │ │ ├── index.js
│ │ │ └── user.js
│ │ ├── theme-install.js
│ │ └── tier
│ │ │ └── new.js
│ ├── setup.js
│ ├── setup
│ │ ├── done.js
│ │ └── index.js
│ ├── signin.js
│ ├── signout.js
│ ├── signup.js
│ ├── site.js
│ ├── tag.js
│ ├── tag
│ │ └── new.js
│ ├── tags.js
│ ├── unauthenticated.js
│ └── whatsnew.js
├── serializers
│ ├── action.js
│ ├── api-key.js
│ ├── application.js
│ ├── custom-theme-setting-list.js
│ ├── email.js
│ ├── integration.js
│ ├── invite.js
│ ├── label.js
│ ├── member.js
│ ├── newsletter.js
│ ├── notification.js
│ ├── page.js
│ ├── post.js
│ ├── role.js
│ ├── setting.js
│ ├── tag.js
│ ├── theme.js
│ ├── tier.js
│ ├── user.js
│ └── webhook.js
├── services
│ ├── ajax.js
│ ├── billing.js
│ ├── clock.js
│ ├── config.js
│ ├── custom-theme-settings.js
│ ├── custom-views.js
│ ├── dashboard-mocks.js
│ ├── dashboard-stats.js
│ ├── data-cache.js
│ ├── dropdown.js
│ ├── event-bus.js
│ ├── feature.js
│ ├── frontend.js
│ ├── ghost-paths.js
│ ├── lazy-loader.js
│ ├── limit.js
│ ├── media-queries.js
│ ├── media.js
│ ├── member-import-validator.js
│ ├── members-count-cache.js
│ ├── members-stats.js
│ ├── members-utils.js
│ ├── modals.js
│ ├── navigation.js
│ ├── notifications.js
│ ├── resize-detector.js
│ ├── session.js
│ ├── settings.js
│ ├── slug-generator.js
│ ├── tenor.js
│ ├── theme-management.js
│ ├── ui.js
│ ├── unsplash.js
│ ├── upgrade-status.js
│ ├── utils.js
│ └── whats-new.js
├── session-stores
│ └── application.js
├── styles
│ ├── app-dark.css
│ ├── app.css
│ ├── components
│ │ ├── badges.css
│ │ ├── browser-preview.css
│ │ ├── codemirror.css
│ │ ├── dropdowns.css
│ │ ├── filter-builder.css
│ │ ├── koenig-dark.css
│ │ ├── koenig.css
│ │ ├── lists.css
│ │ ├── loading-indicator.css
│ │ ├── modals-new.css
│ │ ├── modals.css
│ │ ├── notifications.css
│ │ ├── pagination.css
│ │ ├── popovers.css
│ │ ├── power-calendar.css
│ │ ├── power-select.css
│ │ ├── publishmenu.css
│ │ ├── settings-menu.css
│ │ ├── splitbuttons.css
│ │ ├── stacks.css
│ │ ├── tabs.css
│ │ ├── unsplash.css
│ │ └── uploader.css
│ ├── layouts
│ │ ├── apps.css
│ │ ├── auth.css
│ │ ├── billing.css
│ │ ├── content.css
│ │ ├── dashboard.css
│ │ ├── editor.css
│ │ ├── error.css
│ │ ├── explore.css
│ │ ├── flow.css
│ │ ├── fullscreen-wizard.css
│ │ ├── labs.css
│ │ ├── main.css
│ │ ├── member-activity.css
│ │ ├── members.css
│ │ ├── offers.css
│ │ ├── packages.css
│ │ ├── portal-settings.css
│ │ ├── post-preview.css
│ │ ├── preview-email.css
│ │ ├── settings.css
│ │ ├── tags.css
│ │ ├── tiers.css
│ │ ├── user.css
│ │ ├── users.css
│ │ └── whatsnew.css
│ ├── patterns
│ │ ├── boxes.css
│ │ ├── buttons.css
│ │ ├── forms.css
│ │ ├── global.css
│ │ ├── icons.css
│ │ ├── labels.css
│ │ ├── navlist.css
│ │ └── tables.css
│ └── spirit
│ │ ├── _animations.css
│ │ ├── _aspect-ratios.css
│ │ ├── _background-position.css
│ │ ├── _background-size.css
│ │ ├── _border-colors.css
│ │ ├── _border-radius.css
│ │ ├── _border-style.css
│ │ ├── _border-widths.css
│ │ ├── _borders.css
│ │ ├── _box-shadow.css
│ │ ├── _box-sizing.css
│ │ ├── _clears.css
│ │ ├── _code.css
│ │ ├── _colors-dark.css
│ │ ├── _colors.css
│ │ ├── _coordinates.css
│ │ ├── _custom-styles-dark.css
│ │ ├── _custom-styles.css
│ │ ├── _debug-children.css
│ │ ├── _debug-grid.css
│ │ ├── _debug.css
│ │ ├── _display.css
│ │ ├── _dropdown.css
│ │ ├── _flexbox.css
│ │ ├── _floats.css
│ │ ├── _font-family.css
│ │ ├── _font-style.css
│ │ ├── _font-weight.css
│ │ ├── _forms.css
│ │ ├── _gradients.css
│ │ ├── _heights.css
│ │ ├── _hovers.css
│ │ ├── _icons.css
│ │ ├── _images.css
│ │ ├── _letter-spacing.css
│ │ ├── _line-height.css
│ │ ├── _links.css
│ │ ├── _lists.css
│ │ ├── _max-widths.css
│ │ ├── _media-queries.css
│ │ ├── _min-heights.css
│ │ ├── _min-widths.css
│ │ ├── _module-template.css
│ │ ├── _negative-margins.css
│ │ ├── _nested.css
│ │ ├── _normalize.css
│ │ ├── _nudge.css
│ │ ├── _opacity.css
│ │ ├── _outlines.css
│ │ ├── _overflow.css
│ │ ├── _pointer-events.css
│ │ ├── _position.css
│ │ ├── _rotations.css
│ │ ├── _skins.css
│ │ ├── _spacing.css
│ │ ├── _tables.css
│ │ ├── _text-align.css
│ │ ├── _text-block-spacings.css
│ │ ├── _text-decoration.css
│ │ ├── _text-transform.css
│ │ ├── _type-scale.css
│ │ ├── _typography.css
│ │ ├── _utilities.css
│ │ ├── _vertical-align.css
│ │ ├── _visibility.css
│ │ ├── _white-space.css
│ │ ├── _widths.css
│ │ ├── _word-break.css
│ │ ├── _z-index.css
│ │ ├── spirit-dark.css
│ │ └── spirit.css
├── templates
│ ├── application-error.hbs
│ ├── application.hbs
│ ├── dashboard.hbs
│ ├── designsandbox.hbs
│ ├── editor.hbs
│ ├── editor
│ │ └── edit-loading.hbs
│ ├── error.hbs
│ ├── explore.hbs
│ ├── launch.hbs
│ ├── member.hbs
│ ├── members-activity.hbs
│ ├── members.hbs
│ ├── members
│ │ └── import.hbs
│ ├── offer.hbs
│ ├── offers.hbs
│ ├── pages-loading.hbs
│ ├── pages.hbs
│ ├── posts-loading.hbs
│ ├── posts.hbs
│ ├── react-editor.hbs
│ ├── react-editor
│ │ └── edit-loading.hbs
│ ├── reset.hbs
│ ├── settings.hbs
│ ├── settings
│ │ ├── code-injection-loading.hbs
│ │ ├── code-injection.hbs
│ │ ├── design
│ │ │ ├── change-theme.hbs
│ │ │ └── index.hbs
│ │ ├── general-loading.hbs
│ │ ├── general.hbs
│ │ ├── integration.hbs
│ │ ├── integration
│ │ │ └── webhooks
│ │ │ │ ├── edit.hbs
│ │ │ │ └── new.hbs
│ │ ├── integrations.hbs
│ │ ├── integrations
│ │ │ ├── amp-loading.hbs
│ │ │ ├── amp.hbs
│ │ │ ├── firstpromoter.hbs
│ │ │ ├── slack-loading.hbs
│ │ │ ├── slack.hbs
│ │ │ ├── unsplash-loading.hbs
│ │ │ ├── unsplash.hbs
│ │ │ └── zapier.hbs
│ │ ├── labs-loading.hbs
│ │ ├── labs.hbs
│ │ ├── membership.hbs
│ │ ├── navigation.hbs
│ │ ├── newsletters.hbs
│ │ └── staff
│ │ │ ├── index.hbs
│ │ │ ├── user-loading.hbs
│ │ │ └── user.hbs
│ ├── setup.hbs
│ ├── setup
│ │ └── done.hbs
│ ├── signin.hbs
│ ├── signup.hbs
│ ├── site.hbs
│ ├── tag.hbs
│ ├── tags-loading.hbs
│ ├── tags.hbs
│ └── whatsnew.hbs
├── transforms
│ ├── facebook-url-user.js
│ ├── json-string.js
│ ├── member-subscription.js
│ ├── member-tier.js
│ ├── members-segment-string.js
│ ├── moment-date.js
│ ├── moment-utc.js
│ ├── navigation-settings.js
│ ├── raw.js
│ ├── tier-benefits.js
│ ├── twitter-url-user.js
│ └── visibility-string.js
├── transitions.js
├── transitions
│ └── wormhole.js
├── utils
│ ├── bound-one-way.js
│ ├── caja-sanitizers.js
│ ├── copy-text-to-clipboard.js
│ ├── ctrl-or-cmd.js
│ ├── currency.js
│ ├── flatten-grouped-options.js
│ ├── format-markdown.js
│ ├── get-scroll-parent.js
│ ├── ghost-paths.js
│ ├── isNumber.js
│ ├── link-component.js
│ ├── password-generator.js
│ ├── publish-options.js
│ ├── route.js
│ ├── shortcuts.js
│ ├── slug-url.js
│ └── window-proxy.js
└── validators
│ ├── base.js
│ ├── custom-view.js
│ ├── integration.js
│ ├── invite-user.js
│ ├── label.js
│ ├── member.js
│ ├── mixins
│ └── password.js
│ ├── nav-item.js
│ ├── new-user.js
│ ├── newsletter.js
│ ├── offer.js
│ ├── post.js
│ ├── reset.js
│ ├── setting.js
│ ├── setup.js
│ ├── signin.js
│ ├── signup.js
│ ├── snippet.js
│ ├── subscriber.js
│ ├── tag-settings.js
│ ├── tier-benefit-item.js
│ ├── tier.js
│ ├── user.js
│ └── webhook.js
├── config
├── coverage.js
├── deprecation-workflow.js
├── environment.js
├── optional-features.json
└── targets.js
├── ember-cli-build.js
├── ember-cli-update.json
├── lib
├── asset-delivery
│ ├── index.js
│ └── package.json
└── koenig-editor
│ ├── addon
│ ├── components
│ │ ├── kg-action-bar.hbs
│ │ ├── kg-action-bar.js
│ │ ├── koenig-alt-input.hbs
│ │ ├── koenig-alt-input.js
│ │ ├── koenig-basic-html-input.hbs
│ │ ├── koenig-basic-html-input.js
│ │ ├── koenig-basic-html-textarea.hbs
│ │ ├── koenig-basic-html-textarea.js
│ │ ├── koenig-caption-input.hbs
│ │ ├── koenig-caption-input.js
│ │ ├── koenig-card-audio.hbs
│ │ ├── koenig-card-audio.js
│ │ ├── koenig-card-before-after.hbs
│ │ ├── koenig-card-before-after.js
│ │ ├── koenig-card-bookmark.hbs
│ │ ├── koenig-card-bookmark.js
│ │ ├── koenig-card-button.hbs
│ │ ├── koenig-card-button.js
│ │ ├── koenig-card-callout.hbs
│ │ ├── koenig-card-callout.js
│ │ ├── koenig-card-code.hbs
│ │ ├── koenig-card-code.js
│ │ ├── koenig-card-email-cta.hbs
│ │ ├── koenig-card-email-cta.js
│ │ ├── koenig-card-email.hbs
│ │ ├── koenig-card-email.js
│ │ ├── koenig-card-embed.hbs
│ │ ├── koenig-card-embed.js
│ │ ├── koenig-card-embed
│ │ │ ├── nft.hbs
│ │ │ └── nft.js
│ │ ├── koenig-card-file.hbs
│ │ ├── koenig-card-file.js
│ │ ├── koenig-card-gallery.hbs
│ │ ├── koenig-card-gallery.js
│ │ ├── koenig-card-header.hbs
│ │ ├── koenig-card-header.js
│ │ ├── koenig-card-hr.hbs
│ │ ├── koenig-card-hr.js
│ │ ├── koenig-card-html.hbs
│ │ ├── koenig-card-html.js
│ │ ├── koenig-card-image.hbs
│ │ ├── koenig-card-image.js
│ │ ├── koenig-card-image
│ │ │ ├── selector-tenor.hbs
│ │ │ ├── selector-tenor.js
│ │ │ └── selector-tenor
│ │ │ │ ├── gif.hbs
│ │ │ │ └── gif.js
│ │ ├── koenig-card-markdown.hbs
│ │ ├── koenig-card-markdown.js
│ │ ├── koenig-card-paywall.hbs
│ │ ├── koenig-card-paywall.js
│ │ ├── koenig-card-product.hbs
│ │ ├── koenig-card-product.js
│ │ ├── koenig-card-toggle.hbs
│ │ ├── koenig-card-toggle.js
│ │ ├── koenig-card-video.hbs
│ │ ├── koenig-card-video.js
│ │ ├── koenig-card.hbs
│ │ ├── koenig-card.js
│ │ ├── koenig-editor.hbs
│ │ ├── koenig-editor.js
│ │ ├── koenig-link-input.hbs
│ │ ├── koenig-link-input.js
│ │ ├── koenig-link-toolbar.hbs
│ │ ├── koenig-link-toolbar.js
│ │ ├── koenig-media-selector.hbs
│ │ ├── koenig-media-selector.js
│ │ ├── koenig-menu-content.hbs
│ │ ├── koenig-menu-content.js
│ │ ├── koenig-plus-menu.hbs
│ │ ├── koenig-plus-menu.js
│ │ ├── koenig-settings-panel.hbs
│ │ ├── koenig-settings-panel.js
│ │ ├── koenig-slash-menu.hbs
│ │ ├── koenig-slash-menu.js
│ │ ├── koenig-snippet-input.hbs
│ │ ├── koenig-snippet-input.js
│ │ ├── koenig-text-replacement-html-input.hbs
│ │ ├── koenig-text-replacement-html-input.js
│ │ ├── koenig-toolbar.hbs
│ │ └── koenig-toolbar.js
│ ├── helpers
│ │ ├── card-is-available.js
│ │ ├── clean-basic-html.js
│ │ ├── kg-style.js
│ │ └── sanitize-html.js
│ ├── lib
│ │ ├── clean-text-replacement-html.js
│ │ ├── dnd
│ │ │ ├── constants.js
│ │ │ ├── container.js
│ │ │ ├── scroll-handler.js
│ │ │ └── utils.js
│ │ └── relative-to-absolute.js
│ ├── options
│ │ ├── atoms.js
│ │ ├── basic-html-parser-plugins.js
│ │ ├── cards.js
│ │ ├── key-commands.js
│ │ └── text-expansions.js
│ ├── services
│ │ ├── koenig-drag-drop-handler.js
│ │ └── koenig-ui.js
│ └── utils
│ │ ├── create-component-atom.js
│ │ ├── create-component-card.js
│ │ ├── extract-audio-metadata.js
│ │ ├── extract-video-metadata.js
│ │ ├── get-scroll-parent.js
│ │ ├── insert-cards-from-files.js
│ │ ├── localstorage.js
│ │ ├── markup-utils.js
│ │ ├── oembed.js
│ │ ├── prettify-file-name.js
│ │ ├── reading-time.js
│ │ └── snippet-icon.js
│ ├── app
│ ├── components
│ │ ├── kg-action-bar.js
│ │ ├── koenig-alt-input.js
│ │ ├── koenig-basic-html-input.js
│ │ ├── koenig-basic-html-textarea.js
│ │ ├── koenig-caption-input.js
│ │ ├── koenig-card-audio.js
│ │ ├── koenig-card-before-after.js
│ │ ├── koenig-card-bookmark.js
│ │ ├── koenig-card-button.js
│ │ ├── koenig-card-callout.js
│ │ ├── koenig-card-code.js
│ │ ├── koenig-card-email-cta.js
│ │ ├── koenig-card-email.js
│ │ ├── koenig-card-embed.js
│ │ ├── koenig-card-embed
│ │ │ └── nft.js
│ │ ├── koenig-card-file.js
│ │ ├── koenig-card-gallery.js
│ │ ├── koenig-card-header.js
│ │ ├── koenig-card-hr.js
│ │ ├── koenig-card-html.js
│ │ ├── koenig-card-image.js
│ │ ├── koenig-card-image
│ │ │ ├── selector-tenor.js
│ │ │ └── selector-tenor
│ │ │ │ └── gif.js
│ │ ├── koenig-card-markdown.js
│ │ ├── koenig-card-paywall.js
│ │ ├── koenig-card-product.js
│ │ ├── koenig-card-toggle.js
│ │ ├── koenig-card-video.js
│ │ ├── koenig-card.js
│ │ ├── koenig-editor.js
│ │ ├── koenig-link-input.js
│ │ ├── koenig-link-toolbar.js
│ │ ├── koenig-media-selector.js
│ │ ├── koenig-menu-content.js
│ │ ├── koenig-plus-menu.js
│ │ ├── koenig-settings-panel.js
│ │ ├── koenig-slash-menu.js
│ │ ├── koenig-snippet-input.js
│ │ ├── koenig-text-replacement-html-input.js
│ │ └── koenig-toolbar.js
│ ├── helpers
│ │ ├── card-is-available.js
│ │ ├── clean-basic-html.js
│ │ ├── kg-style.js
│ │ └── sanitize-html.js
│ └── services
│ │ ├── koenig-drag-drop-handler.js
│ │ └── koenig-ui.js
│ ├── docs
│ └── specs
│ │ └── popup-toolbar.md
│ ├── index.js
│ ├── package.json
│ └── public
│ └── icons
│ └── koenig
│ ├── card-indicator-email.svg
│ ├── card-indicator-html.svg
│ ├── card-indicator-markdown.svg
│ ├── code-block.svg
│ ├── kg-add.svg
│ ├── kg-bold.svg
│ ├── kg-card-type-audio.svg
│ ├── kg-card-type-before-after.svg
│ ├── kg-card-type-bookmark.svg
│ ├── kg-card-type-button.svg
│ ├── kg-card-type-callout.svg
│ ├── kg-card-type-codepen.svg
│ ├── kg-card-type-divider.svg
│ ├── kg-card-type-email-cta.svg
│ ├── kg-card-type-email.svg
│ ├── kg-card-type-facebook.svg
│ ├── kg-card-type-file.svg
│ ├── kg-card-type-gallery.svg
│ ├── kg-card-type-gen-embed.svg
│ ├── kg-card-type-gif.svg
│ ├── kg-card-type-header.svg
│ ├── kg-card-type-html.svg
│ ├── kg-card-type-image.svg
│ ├── kg-card-type-instagram.svg
│ ├── kg-card-type-markdown.svg
│ ├── kg-card-type-nft.svg
│ ├── kg-card-type-other.svg
│ ├── kg-card-type-paywall.svg
│ ├── kg-card-type-product.svg
│ ├── kg-card-type-snippet-block.svg
│ ├── kg-card-type-snippet-combination.svg
│ ├── kg-card-type-snippet-text.svg
│ ├── kg-card-type-soundcloud.svg
│ ├── kg-card-type-spotify.svg
│ ├── kg-card-type-toggle.svg
│ ├── kg-card-type-twitter.svg
│ ├── kg-card-type-unsplash.svg
│ ├── kg-card-type-video.svg
│ ├── kg-card-type-vimeo.svg
│ ├── kg-card-type-youtube.svg
│ ├── kg-cta-border.svg
│ ├── kg-edit.svg
│ ├── kg-header-full-center.svg
│ ├── kg-header-full-left.svg
│ ├── kg-header-full-right.svg
│ ├── kg-header-wide-center.svg
│ ├── kg-header-wide-left.svg
│ ├── kg-header-wide-right.svg
│ ├── kg-heading-1.svg
│ ├── kg-heading-2.svg
│ ├── kg-img-full.svg
│ ├── kg-img-regular.svg
│ ├── kg-img-wide.svg
│ ├── kg-italic.svg
│ ├── kg-link.svg
│ ├── kg-quote-1.svg
│ ├── kg-quote-2.svg
│ ├── kg-quote.svg
│ ├── kg-replace.svg
│ ├── kg-snippet.svg
│ ├── kg-star.svg
│ ├── kg-thin-delete.svg
│ ├── kg-thin-edit.svg
│ ├── kg-toggle-card-open-arrow.svg
│ └── kg-trash.svg
├── mirage
├── .eslintrc.js
├── config.js
├── config
│ ├── api-keys.js
│ ├── authentication.js
│ ├── config.js
│ ├── custom-theme-settings.js
│ ├── emails.js
│ ├── integrations.js
│ ├── invites.js
│ ├── labels.js
│ ├── members.js
│ ├── newsletters.js
│ ├── offers.js
│ ├── pages.js
│ ├── posts.js
│ ├── roles.js
│ ├── settings.js
│ ├── site.js
│ ├── slugs.js
│ ├── snippets.js
│ ├── stats.js
│ ├── tags.js
│ ├── themes.js
│ ├── tiers.js
│ ├── uploads.js
│ ├── users.js
│ └── webhooks.js
├── factories
│ ├── api-key.js
│ ├── email.js
│ ├── integration.js
│ ├── invite.js
│ ├── label.js
│ ├── member-activity-event.js
│ ├── member.js
│ ├── notification.js
│ ├── offer.js
│ ├── post.js
│ ├── role.js
│ ├── subscription.js
│ ├── tag.js
│ ├── tier.js
│ ├── user.js
│ └── webhook.js
├── fixtures
│ ├── configs.js
│ ├── newsletters.js
│ ├── roles.js
│ ├── settings.js
│ ├── sites.js
│ ├── themes.js
│ ├── tiers.js
│ └── timezones.js
├── models
│ ├── api-key.js
│ ├── config.js
│ ├── custom-theme-setting.js
│ ├── email.js
│ ├── integration.js
│ ├── invite.js
│ ├── label.js
│ ├── member-activity-event.js
│ ├── member.js
│ ├── newsletter.js
│ ├── notification.js
│ ├── page.js
│ ├── post.js
│ ├── role.js
│ ├── site.js
│ ├── snippet.js
│ ├── subscriber.js
│ ├── subscription.js
│ ├── tag.js
│ ├── theme.js
│ ├── tier.js
│ ├── user.js
│ └── webhook.js
├── routes-dev.js
├── routes-test.js
├── scenarios
│ └── default.js
├── serializers
│ ├── application.js
│ ├── integration.js
│ ├── label.js
│ ├── member-activity-event.js
│ ├── member.js
│ ├── page.js
│ ├── post.js
│ ├── subscription.js
│ ├── tag.js
│ ├── tier.js
│ └── user.js
└── utils.js
├── package.json
├── public
└── assets
│ ├── fonts
│ └── Inter.ttf
│ ├── icons
│ ├── account-group.svg
│ ├── activity-placeholder.svg
│ ├── add-stroke.svg
│ ├── add-view.svg
│ ├── add.svg
│ ├── align-center.svg
│ ├── align-left.svg
│ ├── ambulance.svg
│ ├── analytics.svg
│ ├── arrow-down-small.svg
│ ├── arrow-down-stroke.svg
│ ├── arrow-down.svg
│ ├── arrow-left-small.svg
│ ├── arrow-left-stroke.svg
│ ├── arrow-left-tail.svg
│ ├── arrow-left.svg
│ ├── arrow-right-small.svg
│ ├── arrow-right-stroke.svg
│ ├── arrow-right-tail.svg
│ ├── arrow-right.svg
│ ├── arrow-up-small.svg
│ ├── arrow-up-stroke.svg
│ ├── arrow-up.svg
│ ├── arrow2-down.svg
│ ├── arrow2-right.svg
│ ├── audio-file.svg
│ ├── audio-upload.svg
│ ├── book-open.svg
│ ├── bookmark-article.svg
│ ├── box-hands.svg
│ ├── box.svg
│ ├── boxes.svg
│ ├── brackets.svg
│ ├── button.svg
│ ├── calendar.svg
│ ├── cash.svg
│ ├── chat-double-bubble.svg
│ ├── check-2.svg
│ ├── check-circle-stroke.svg
│ ├── check-circle.svg
│ ├── check.svg
│ ├── cheeseburger.svg
│ ├── circle-ellipsis.svg
│ ├── clock.svg
│ ├── clockface.svg
│ ├── close-stroke.svg
│ ├── close.svg
│ ├── cloud.svg
│ ├── compass-2.svg
│ ├── compass.svg
│ ├── computer.svg
│ ├── confetti.svg
│ ├── content-bold.svg
│ ├── content.svg
│ ├── copy.svg
│ ├── credit-card.svg
│ ├── cross-circle.svg
│ ├── cycle.svg
│ ├── default-favicon.svg
│ ├── desert.svg
│ ├── desktop.svg
│ ├── diamond.svg
│ ├── discount-bubble.svg
│ ├── dividers.svg
│ ├── dotdotdot.svg
│ ├── download-circle.svg
│ ├── download.svg
│ ├── eco-globe.svg
│ ├── eco-lightbulb.svg
│ ├── edit-view.svg
│ ├── ellipsis.svg
│ ├── email-at.svg
│ ├── email-body.svg
│ ├── email-footer.svg
│ ├── email-header.svg
│ ├── email-love-letter.svg
│ ├── email-member.svg
│ ├── email-name.svg
│ ├── email-send.svg
│ ├── email-stroke.svg
│ ├── email-unread.svg
│ ├── email.svg
│ ├── event-canceled-subscription.svg
│ ├── event-comment.svg
│ ├── event-email-delivery-failed.svg
│ ├── event-logged-in.svg
│ ├── event-made-a-payment.svg
│ ├── event-opened-email.svg
│ ├── event-received-email.svg
│ ├── event-signed-up.svg
│ ├── event-subscribed-to-email.svg
│ ├── event-subscriptions.svg
│ ├── event-unsubscribed-from-email.svg
│ ├── expand.svg
│ ├── external.svg
│ ├── eye.svg
│ ├── facebook-heart.svg
│ ├── facebook-like.svg
│ ├── facebook.svg
│ ├── feature-image.svg
│ ├── file-download.svg
│ ├── file-tabular-data.svg
│ ├── file-text-document.svg
│ ├── file-upload.svg
│ ├── film-camera.svg
│ ├── filter.svg
│ ├── firstpromoter.png
│ ├── folder.svg
│ ├── gallery-placeholder.svg
│ ├── get-started-import.svg
│ ├── get-started-members.svg
│ ├── get-started-migrations.svg
│ ├── get-started.svg
│ ├── ghost-logo-orb.svg
│ ├── ghost-logo.svg
│ ├── ghost-orb.svg
│ ├── ghost-squircle.svg
│ ├── gift.svg
│ ├── github-outline.svg
│ ├── github-star.svg
│ ├── github.svg
│ ├── globe.svg
│ ├── google-favicon.svg
│ ├── google-search.svg
│ ├── google.svg
│ ├── grab.svg
│ ├── graph-line.svg
│ ├── heart-beat.svg
│ ├── heart-circle.svg
│ ├── heart.svg
│ ├── help.svg
│ ├── hotspot.svg
│ ├── house-bold.svg
│ ├── house.svg
│ ├── icon.svg
│ ├── id-card.svg
│ ├── idea.svg
│ ├── info.svg
│ ├── instagram.svg
│ ├── integration.svg
│ ├── labs.svg
│ ├── laptop.svg
│ ├── line.svg
│ ├── link.svg
│ ├── list-bullet.svg
│ ├── list-number.svg
│ ├── lock.svg
│ ├── lock2.svg
│ ├── loop-infinite.svg
│ ├── lotus.svg
│ ├── markdown.svg
│ ├── member-add.svg
│ ├── member.svg
│ ├── members-all.svg
│ ├── members-bold.svg
│ ├── members-outline.svg
│ ├── members-paid.svg
│ ├── members-placeholder.svg
│ ├── members-post.svg
│ ├── members-segment.svg
│ ├── members.svg
│ ├── mobile-phone-heart.svg
│ ├── mobile-phone.svg
│ ├── module.svg
│ ├── modules.svg
│ ├── monitor-labs.svg
│ ├── moon.svg
│ ├── mountains.svg
│ ├── mute.svg
│ ├── navigation.svg
│ ├── network.svg
│ ├── news-article.svg
│ ├── nightshift.svg
│ ├── no-data-line-chart.svg
│ ├── no-data-list.svg
│ ├── no-data-subscription.svg
│ ├── no-email.svg
│ ├── no-members.svg
│ ├── offer.svg
│ ├── page-bold.svg
│ ├── page.svg
│ ├── pages-placeholder.svg
│ ├── paint-palette.svg
│ ├── paintbrush.svg
│ ├── pause.svg
│ ├── pen.svg
│ ├── pencil-circle.svg
│ ├── pencil.svg
│ ├── percentage.svg
│ ├── photos-people.svg
│ ├── photos.svg
│ ├── piggy-bank.svg
│ ├── pin.svg
│ ├── plane.svg
│ ├── play.svg
│ ├── plus.svg
│ ├── portal-icon-1.svg
│ ├── portal-icon-2.svg
│ ├── portal-icon-3.svg
│ ├── portal-icon-4.svg
│ ├── portal-icon-5.svg
│ ├── portal-logo-stroke.svg
│ ├── portal-logo.svg
│ ├── post.svg
│ ├── posts-placeholder.svg
│ ├── posts.svg
│ ├── powered-by-stripe.svg
│ ├── powered-by-tenor.svg
│ ├── presentation-code.svg
│ ├── published-post.svg
│ ├── recycle.svg
│ ├── reload.svg
│ ├── repo.svg
│ ├── retry.svg
│ ├── satellite.svg
│ ├── search.svg
│ ├── send-email.svg
│ ├── server.svg
│ ├── settings.svg
│ ├── shield-lock.svg
│ ├── shield.svg
│ ├── sidemenu-open.svg
│ ├── sidemenu.svg
│ ├── signal-tower.svg
│ ├── signout.svg
│ ├── smiley.svg
│ ├── social-facebook.svg
│ ├── social-share.svg
│ ├── social-twitter.svg
│ ├── spinner.svg
│ ├── staff.svg
│ ├── star-filled.svg
│ ├── store.svg
│ ├── stripe-verified-partner-badge.svg
│ ├── summer.svg
│ ├── sun.svg
│ ├── support.svg
│ ├── sync.svg
│ ├── tag.svg
│ ├── tags-placeholder.svg
│ ├── tenor.svg
│ ├── terminal.svg
│ ├── text-vector.svg
│ ├── text.svg
│ ├── theme.svg
│ ├── ticket.svg
│ ├── trash.svg
│ ├── trophy.svg
│ ├── tumbleweed.svg
│ ├── twitter-comment.svg
│ ├── twitter-like.svg
│ ├── twitter-link.svg
│ ├── twitter-logo.svg
│ ├── twitter-retweet.svg
│ ├── twitter-share.svg
│ ├── twitter.svg
│ ├── ufo-attack.svg
│ ├── unmute.svg
│ ├── unsplash-heart.svg
│ ├── unsplash.svg
│ ├── unsubscribed.svg
│ ├── upload-fill.svg
│ ├── upload.svg
│ ├── user-circle.svg
│ ├── user-group.svg
│ ├── user-group2.svg
│ ├── v-ellipsis.svg
│ ├── view-site.svg
│ ├── warning-stroke.svg
│ ├── warning.svg
│ ├── window-app.svg
│ ├── window-pulse.svg
│ ├── wrench-double.svg
│ └── zap.svg
│ └── img
│ ├── 404-ghost.png
│ ├── 404-ghost@2x.png
│ ├── abstract-2.jpg
│ ├── abstract.jpg
│ ├── amp.svg
│ ├── apple-touch-icon.png
│ ├── buffer.png
│ ├── community-background.jpg
│ ├── community.jpg
│ ├── dashboard-feature-image.jpeg
│ ├── dashboard
│ ├── bp1.jpg
│ ├── bp2.jpg
│ └── join-community.jpg
│ ├── disqus.svg
│ ├── favicon.ico
│ ├── firstpromoter.png
│ ├── footer-marketplace-bg.png
│ ├── get-started.jpg
│ ├── github.svg
│ ├── google-analytics.png
│ ├── google-docs.svg
│ ├── install-welcome.png
│ ├── invite-placeholder.png
│ ├── large.png
│ ├── launch-wizard-bg.png
│ ├── loadingcat.gif
│ ├── logos
│ ├── ghost-logo-black-1.png
│ ├── orb-black-1.png
│ ├── orb-black-2.png
│ ├── orb-black-3.png
│ ├── orb-black-4.png
│ └── orb-black-5.png
│ ├── mailchimp.svg
│ ├── marketing
│ ├── members-1.jpg
│ ├── members-2.jpg
│ ├── offers-1.jpg
│ ├── offers-2.jpg
│ └── offers-3.jpg
│ ├── medium.png
│ ├── more.png
│ ├── newsletter-1.jpg
│ ├── newsletter-2.jpg
│ ├── orb-squircle.png
│ ├── patreon.svg
│ ├── paypal.svg
│ ├── plausible.png
│ ├── resource-1.jpg
│ ├── slackicon.png
│ ├── small.png
│ ├── themes
│ ├── Alto-cut.jpg
│ ├── Alto.jpg
│ ├── Alto.png
│ ├── Bulletin.png
│ ├── Casper.jpg
│ ├── Dawn.png
│ ├── Digest.png
│ ├── Dope.png
│ ├── Ease-cut.jpg
│ ├── Ease.jpg
│ ├── Ease.png
│ ├── Edge.png
│ ├── Edition-cut.jpg
│ ├── Edition.jpg
│ ├── Edition.png
│ ├── Headline.jpg
│ ├── Journal.png
│ ├── London-cut.jpg
│ ├── London.jpg
│ ├── Ruby.png
│ └── Wave.png
│ ├── touch-icon-ipad.png
│ ├── touch-icon-iphone.png
│ ├── twitter.svg
│ ├── typeform.svg
│ ├── ulysses.png
│ ├── unsplash-404.png
│ ├── user-cover.png
│ ├── user-image.png
│ ├── users.png
│ ├── whats-new-header-bg.svg
│ ├── zapier-logo.svg
│ ├── zapier.svg
│ └── zero-bounce.png
├── renovate.json
├── testem.js
├── tests
├── .eslintrc.js
├── acceptance
│ ├── authentication-test.js
│ ├── content-test.js
│ ├── custom-post-templates-test.js
│ ├── dashboard-test.js
│ ├── editor-test.js
│ ├── editor
│ │ └── publish-flow-test.js
│ ├── error-handling-test.js
│ ├── launch-flow-test.js
│ ├── members-activity-test.js
│ ├── members-test.js
│ ├── members
│ │ ├── details-test.js
│ │ ├── filter-test.js
│ │ └── import-test.js
│ ├── offers-test.js
│ ├── password-reset-test.js
│ ├── settings
│ │ ├── amp-test.js
│ │ ├── code-injection-test.js
│ │ ├── design-test.js
│ │ ├── general-test.js
│ │ ├── integrations-test.js
│ │ ├── labs-test.js
│ │ ├── membership-test.js
│ │ ├── navigation-test.js
│ │ ├── newsletters-test.js
│ │ ├── slack-test.js
│ │ ├── tags-test.js
│ │ ├── unsplash-test.js
│ │ └── zapier-test.js
│ ├── setup-test.js
│ ├── signin-test.js
│ ├── signup-test.js
│ └── staff-test.js
├── helpers
│ ├── file-upload.js
│ ├── labs-flag.js
│ ├── login-as-role.js
│ ├── mailgun.js
│ ├── members.js
│ ├── newsletters.js
│ ├── stripe.js
│ └── visit.js
├── index.html
├── integration
│ ├── adapters
│ │ ├── tag-test.js
│ │ └── user-test.js
│ ├── components
│ │ ├── gh-alert-test.js
│ │ ├── gh-alerts-test.js
│ │ ├── gh-basic-dropdown-test.js
│ │ ├── gh-cm-editor-test.js
│ │ ├── gh-date-picker-test.js
│ │ ├── gh-date-time-picker-test.js
│ │ ├── gh-distribution-action-select-test.js
│ │ ├── gh-feature-flag-test.js
│ │ ├── gh-file-uploader-test.js
│ │ ├── gh-image-uploader-test.js
│ │ ├── gh-image-uploader-with-preview-test.js
│ │ ├── gh-member-avatar-test.js
│ │ ├── gh-members-import-table-test.js
│ │ ├── gh-navitem-test.js
│ │ ├── gh-navitem-url-input-test.js
│ │ ├── gh-notification-test.js
│ │ ├── gh-notifications-test.js
│ │ ├── gh-psm-tags-input-test.js
│ │ ├── gh-psm-template-select-test.js
│ │ ├── gh-psm-visibility-input-test.js
│ │ ├── gh-search-input-test.js
│ │ ├── gh-tag-settings-form-test.js
│ │ ├── gh-task-button-test.js
│ │ ├── gh-theme-table-test.js
│ │ ├── gh-timezone-select-test.js
│ │ ├── gh-trim-focus-input-test.js
│ │ ├── gh-unsplash-photo-test.js
│ │ ├── gh-unsplash-test.js
│ │ ├── gh-uploader-test.js
│ │ ├── gh-validation-status-container-test.js
│ │ ├── gh-whats-new-test.js
│ │ ├── koenig-toolbar-test.js
│ │ ├── modal-import-members-test.js
│ │ └── modal-transfer-owner-test.js
│ ├── helpers
│ │ ├── background-image-style-test.js
│ │ ├── clean-basic-html-test.js
│ │ ├── gh-format-post-time-test.js
│ │ ├── gh-url-preview-test.js
│ │ └── sanitize-html-test.js
│ └── services
│ │ ├── ajax-test.js
│ │ ├── config-test.js
│ │ ├── feature-test.js
│ │ ├── lazy-loader-test.js
│ │ ├── member-import-validator-test.js
│ │ ├── slug-generator-test.js
│ │ └── store-test.js
├── test-helper.js
└── unit
│ ├── .gitkeep
│ ├── authenticators
│ └── cookie-test.js
│ ├── components
│ └── gh-post-settings-menu-test.js
│ ├── controllers
│ ├── editor-test.js
│ └── settings
│ │ └── design-test.js
│ ├── helpers
│ ├── gh-count-characters-test.js
│ ├── gh-count-down-characters-test.js
│ ├── gh-user-can-admin-test.js
│ ├── highlighted-text-test.js
│ └── most-recently-updated-test.js
│ ├── mixins
│ └── validation-engine-test.js
│ ├── models
│ ├── invite-test.js
│ ├── member-test.js
│ ├── navigation-item-test.js
│ ├── post-test.js
│ ├── role-test.js
│ ├── setting-test.js
│ ├── tag-test.js
│ └── user-test.js
│ ├── routes
│ └── explore-test.js
│ ├── serializers
│ └── notification-test.js
│ ├── services
│ ├── event-bus-test.js
│ ├── limit-test.js
│ ├── member-stats-test.js
│ ├── notifications-test.js
│ └── unsplash-test.js
│ ├── transforms
│ ├── facebook-url-user-test.js
│ ├── json-string-test.js
│ ├── navigation-settings-test.js
│ └── twitter-url-user-test.js
│ ├── utils
│ └── ghost-paths-test.js
│ └── validators
│ ├── nav-item-test.js
│ ├── post-test.js
│ └── tag-settings-test.js
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 |
3 | root = true
4 |
5 | [*]
6 | charset = utf-8
7 | indent_style = space
8 | indent_size = 4
9 | end_of_line = lf
10 | insert_final_newline = true
11 | trim_trailing_whitespace = true
12 |
13 | [*.hbs]
14 | insert_final_newline = false
15 |
16 | [{package,bower}.json]
17 | indent_size = 2
18 |
19 | [*.{diff,md}]
20 | trim_trailing_whitespace = false
21 |
22 | [*.yml]
23 | indent_size = 2
24 |
25 | [Makefile]
26 | indent_style = tab
27 |
--------------------------------------------------------------------------------
/.ember-cli:
--------------------------------------------------------------------------------
1 | {
2 | "component-structure": "flat",
3 | "component-class": "@glimmer/component",
4 | /**
5 | Ember CLI sends analytics information by default. The data is completely
6 | anonymous, but there are times when you might want to disable this behavior.
7 |
8 | Setting `disableAnalytics` to true will prevent any data from being sent.
9 | */
10 | "disableAnalytics": true
11 | }
12 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | # unconventional js
2 | /blueprints/*/files/
3 | /vendor/
4 |
5 | # compiled output
6 | /dist/
7 | /tmp/
8 |
9 | # dependencies
10 | /bower_components/
11 | /node_modules/
12 |
13 | # misc
14 | /coverage/
15 | .eslintcache
16 |
17 | # ember-try
18 | /.node_modules.ember-try/
19 | /bower.json.ember-try
20 | /package.json.ember-try
21 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | Got some code for us? Awesome 🎊!
2 |
3 | Please include a description of your change & check your PR against this list, thanks!
4 |
5 | - [ ] There's a clear use-case for this code change
6 | - [ ] Commit message has a short title & references relevant issues
7 | - [ ] The build will pass (run `ember test` from the repo root - will be `core/admin` if working from the submodule in Ghost).
8 |
9 | More info can be found by clicking the "guidelines for contributing" link above.
10 |
--------------------------------------------------------------------------------
/.lint-todorc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | 'ember-template-lint': {
3 | daysToDecay: {
4 | warn: 120,
5 | error: 180,
6 | }
7 | }
8 | };
9 |
--------------------------------------------------------------------------------
/.template-lintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: "recommended",
3 |
4 | rules: {
5 | 'no-forbidden-elements': ['meta', 'html', 'script'],
6 | 'no-implicit-this': {allow: ['noop', 'now', 'site-icon-style', 'accent-color-background']},
7 | 'no-inline-styles': false
8 | }
9 | };
10 |
--------------------------------------------------------------------------------
/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {
2 | "ignore_dirs": ["tmp", "dist"]
3 | }
4 |
--------------------------------------------------------------------------------
/app/adapters/application.js:
--------------------------------------------------------------------------------
1 | import EmbeddedRelationAdapter from 'ghost-admin/adapters/embedded-relation-adapter';
2 | import classic from 'ember-classic-decorator';
3 |
4 | @classic
5 | export default class Application extends EmbeddedRelationAdapter {
6 | shouldBackgroundReloadRecord() {
7 | return false;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/app/adapters/email.js:
--------------------------------------------------------------------------------
1 | import ApplicationAdapter from './application';
2 | import classic from 'ember-classic-decorator';
3 |
4 | @classic
5 | export default class Email extends ApplicationAdapter {
6 | retry(model) {
7 | let url = `${this.buildURL('email', model.get('id'))}retry/`;
8 |
9 | return this.ajax(url, 'PUT', {data: {}}).then((data) => {
10 | this.store.pushPayload(data);
11 | return model;
12 | });
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/adapters/label.js:
--------------------------------------------------------------------------------
1 | import ApplicationAdapter from 'ghost-admin/adapters/application';
2 | import SlugUrl from 'ghost-admin/utils/slug-url';
3 | import classic from 'ember-classic-decorator';
4 |
5 | @classic
6 | export default class Label extends ApplicationAdapter {
7 | buildURL(_modelName, _id, _snapshot, _requestType, query) {
8 | let url = super.buildURL(...arguments);
9 |
10 | return SlugUrl(url, query);
11 | }
12 | }
--------------------------------------------------------------------------------
/app/adapters/page.js:
--------------------------------------------------------------------------------
1 | import ApplicationAdapter from 'ghost-admin/adapters/application';
2 | import classic from 'ember-classic-decorator';
3 |
4 | @classic
5 | export default class Page extends ApplicationAdapter {
6 | // posts and pages now include everything by default
7 | buildIncludeURL(store, modelName, id, snapshot, requestType, query) {
8 | return this.buildURL(modelName, id, snapshot, requestType, query);
9 | }
10 |
11 | buildQuery(store, modelName, options) {
12 | return options;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/adapters/tag.js:
--------------------------------------------------------------------------------
1 | import ApplicationAdapter from 'ghost-admin/adapters/application';
2 | import SlugUrl from 'ghost-admin/utils/slug-url';
3 | import classic from 'ember-classic-decorator';
4 |
5 | @classic
6 | export default class Tag extends ApplicationAdapter {
7 | buildURL(_modelName, _id, _snapshot, _requestType, query) {
8 | let url = super.buildURL(...arguments);
9 |
10 | return SlugUrl(url, query);
11 | }
12 | }
--------------------------------------------------------------------------------
/app/adapters/theme.js:
--------------------------------------------------------------------------------
1 | import ApplicationAdapter from './application';
2 | import classic from 'ember-classic-decorator';
3 |
4 | @classic
5 | export default class Theme extends ApplicationAdapter {
6 | activate(model) {
7 | let url = `${this.buildURL('theme', model.get('id'))}activate/`;
8 |
9 | return this.ajax(url, 'PUT', {data: {}}).then((data) => {
10 | this.store.pushPayload(data);
11 | return model;
12 | });
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/components/aspect-ratio-box.hbs:
--------------------------------------------------------------------------------
1 | {{#unless this.isResizing}}
2 | {{yield}}
3 | {{/unless}}
--------------------------------------------------------------------------------
/app/components/dashboard/parts/percentage.hbs:
--------------------------------------------------------------------------------
1 | {{#if (gt @percentage 0) }}
2 |
+{{ @percentage }}%
3 | {{else if (lt @percentage 0)}}
4 | {{ @percentage }}%
5 | {{else}}
6 | 0%
7 | {{/if}}
--------------------------------------------------------------------------------
/app/components/dashboard/parts/zero.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Welcome to your Dashboard
4 |
You'll find member analytics here once
someone signs up.
5 |
Add or import members →
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/components/editor/modals/preview/browser.js:
--------------------------------------------------------------------------------
1 | import Component from '@glimmer/component';
2 | import copyTextToClipboard from 'ghost-admin/utils/copy-text-to-clipboard';
3 | import {task, timeout} from 'ember-concurrency';
4 |
5 | export default class ModalPostPreviewBrowserComponent extends Component {
6 | @task
7 | *copyPreviewUrl() {
8 | copyTextToClipboard(this.args.post.previewUrl);
9 | yield timeout(this.isTesting ? 50 : 3000);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/app/components/editor/modals/preview/mobile.hbs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/components/editor/modals/preview/mobile.js:
--------------------------------------------------------------------------------
1 | import Component from '@glimmer/component';
2 | import copyTextToClipboard from 'ghost-admin/utils/copy-text-to-clipboard';
3 | import {task, timeout} from 'ember-concurrency';
4 |
5 | export default class ModalPostPreviewBrowserComponent extends Component {
6 | @task
7 | *copyPreviewUrl() {
8 | copyTextToClipboard(this.args.post.previewUrl);
9 | yield timeout(this.isTesting ? 50 : 3000);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/app/components/editor/modals/publish-flow/options.js:
--------------------------------------------------------------------------------
1 | import Component from '@glimmer/component';
2 | import {action} from '@ember/object';
3 | import {tracked} from '@glimmer/tracking';
4 |
5 | export default class PublishFlowOptions extends Component {
6 | @tracked openSection = null;
7 |
8 | @action
9 | toggleSection(section) {
10 | if (section === this.openSection) {
11 | this.openSection = null;
12 | } else {
13 | this.openSection = section;
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/components/editor/publish-management.hbs:
--------------------------------------------------------------------------------
1 | {{yield (hash
2 | post=@post
3 | publishOptions=this.publishOptions
4 | openPreview=this.openPreview
5 | togglePreview=this.togglePreview
6 | saveTask=this.saveTask
7 | saveButtonTaskGroup=this.saveButtonTaskGroup
8 | hasUnsavedChanges=@hasUnsavedChanges
9 | openPublishFlow=this.openPublishFlow
10 | openUpdateFlow=this.openUpdateFlow
11 | )}}
12 |
--------------------------------------------------------------------------------
/app/components/editor/publish-options/publish-type.js:
--------------------------------------------------------------------------------
1 | import Component from '@glimmer/component';
2 | import {action} from '@ember/object';
3 |
4 | export default class PublishTypeOption extends Component {
5 | @action
6 | onChange(event) {
7 | event.preventDefault();
8 | this.args.publishOptions.setPublishType(event.target.value);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/app/components/epm-modal-container.js:
--------------------------------------------------------------------------------
1 | import EpmModalContainer from '@tryghost/ember-promise-modals/components/modal-container';
2 |
3 | export default class extends EpmModalContainer {}
4 |
--------------------------------------------------------------------------------
/app/components/gh-alert.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{@message.message}}
4 |
5 |
8 |
--------------------------------------------------------------------------------
/app/components/gh-alerts.hbs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/components/gh-alerts.js:
--------------------------------------------------------------------------------
1 | import Component from '@glimmer/component';
2 | import {inject as service} from '@ember/service';
3 |
4 | export default class GhAlerts extends Component {
5 | @service notifications;
6 | }
7 |
--------------------------------------------------------------------------------
/app/components/gh-app.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{yield}}
3 |
4 |
--------------------------------------------------------------------------------
/app/components/gh-basic-dropdown.js:
--------------------------------------------------------------------------------
1 | import BasicDropdown from 'ember-basic-dropdown/components/basic-dropdown';
2 | import {inject as service} from '@ember/service';
3 |
4 | class GhBasicDropdown extends BasicDropdown {
5 | @service dropdown;
6 |
7 | constructor() {
8 | super(...arguments);
9 | this.dropdown.on('close', this, this.close);
10 | }
11 |
12 | willDestroy() {
13 | this.dropdown.off('close', this, this.close);
14 | }
15 | }
16 |
17 | export default GhBasicDropdown;
18 |
--------------------------------------------------------------------------------
/app/components/gh-billing-iframe.hbs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/components/gh-billing-modal.hbs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/components/gh-billing-modal.js:
--------------------------------------------------------------------------------
1 | import Component from '@ember/component';
2 | import classic from 'ember-classic-decorator';
3 | import {computed} from '@ember/object';
4 | import {inject as service} from '@ember/service';
5 |
6 | @classic
7 | export default class GhBillingModal extends Component {
8 | @service billing;
9 |
10 | @computed('billingWindowOpen')
11 | get visibilityClass() {
12 | return this.billingWindowOpen ? 'gh-billing' : 'gh-billing closed';
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/components/gh-billing-update-button.hbs:
--------------------------------------------------------------------------------
1 | {{#if this.showUpgradeButton}}
2 |
3 | {{/if}}
4 |
--------------------------------------------------------------------------------
/app/components/gh-blog-url.hbs:
--------------------------------------------------------------------------------
1 | {{{this.config.blogUrl}}}
--------------------------------------------------------------------------------
/app/components/gh-blog-url.js:
--------------------------------------------------------------------------------
1 | import Component from '@ember/component';
2 | import classic from 'ember-classic-decorator';
3 | import {inject as service} from '@ember/service';
4 | import {tagName} from '@ember-decorators/component';
5 |
6 | @classic
7 | @tagName('')
8 | export default class GhBlogUrl extends Component {
9 | @service config;
10 | }
11 |
--------------------------------------------------------------------------------
/app/components/gh-browser-preview.js:
--------------------------------------------------------------------------------
1 | import Component from '@glimmer/component';
2 | import {inject as service} from '@ember/service';
3 |
4 | export default class GhBrowserPreview extends Component {
5 | @service settings;
6 | }
7 |
--------------------------------------------------------------------------------
/app/components/gh-canvas-header.hbs:
--------------------------------------------------------------------------------
1 |
5 |
8 |
--------------------------------------------------------------------------------
/app/components/gh-cm-editor.hbs:
--------------------------------------------------------------------------------
1 | {{!-- display a standard textarea whilst waiting for CodeMirror to load/initialize --}}
2 |
7 |
--------------------------------------------------------------------------------
/app/components/gh-custom-view-title.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{or @title "No @title provided"}}
3 | {{#if this.customViews.activeView}}
4 | {{svg-jar "arrow-right"}}
5 | {{this.customViews.activeView.name}}
6 | {{/if}}
7 |
--------------------------------------------------------------------------------
/app/components/gh-custom-view-title.js:
--------------------------------------------------------------------------------
1 | import Component from '@glimmer/component';
2 | import {inject as service} from '@ember/service';
3 |
4 | export default class GhCustomViewTitleComponent extends Component {
5 | @service customViews;
6 | @service router;
7 | }
8 |
--------------------------------------------------------------------------------
/app/components/gh-email-preview-link.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{~#if (has-block)~}}
3 | {{~yield~}}
4 | {{else}}
5 | {{~or @data.subject @data.email.subject~}}
6 | {{/if}}
7 |
--------------------------------------------------------------------------------
/app/components/gh-email-preview-link.js:
--------------------------------------------------------------------------------
1 | import Component from '@glimmer/component';
2 | import EmailPreviewModal from './modals/email-preview';
3 | import {action} from '@ember/object';
4 | import {inject as service} from '@ember/service';
5 |
6 | export default class GhEmailPreviewLink extends Component {
7 | @service modals;
8 |
9 | @action
10 | openPreview(event) {
11 | event.preventDefault();
12 | return this.modals.open(EmailPreviewModal, this.args.data);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/components/gh-error-message.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{this.message}}
3 |
4 |
--------------------------------------------------------------------------------
/app/components/gh-feature-flag.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{{yield}}}
4 |
--------------------------------------------------------------------------------
/app/components/gh-file-upload.hbs:
--------------------------------------------------------------------------------
1 |
2 |
5 |
--------------------------------------------------------------------------------
/app/components/gh-form-group.js:
--------------------------------------------------------------------------------
1 | import ValidationStatusContainer from 'ghost-admin/components/gh-validation-status-container';
2 | import classic from 'ember-classic-decorator';
3 | import {classNames} from '@ember-decorators/component';
4 |
5 | @classic
6 | @classNames('form-group')
7 | export default class GhFormGroup extends ValidationStatusContainer {}
8 |
--------------------------------------------------------------------------------
/app/components/gh-html-iframe.hbs:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/components/gh-infinity-loader.js:
--------------------------------------------------------------------------------
1 | import InfinityLoader from 'ember-infinity/components/infinity-loader';
2 | import classic from 'ember-classic-decorator';
3 |
4 | @classic
5 | export default class GhInfinityLoader extends InfinityLoader {}
6 |
--------------------------------------------------------------------------------
/app/components/gh-input-with-select/suggested-option.hbs:
--------------------------------------------------------------------------------
1 | {{@option.text}}{{svg-jar "add"}}
--------------------------------------------------------------------------------
/app/components/gh-link-to-custom-views-index.hbs:
--------------------------------------------------------------------------------
1 |
9 | {{yield}}
10 |
--------------------------------------------------------------------------------
/app/components/gh-loading-spinner.hbs:
--------------------------------------------------------------------------------
1 | {{#if this.showSpinner}}
2 |
5 | {{/if}}
--------------------------------------------------------------------------------
/app/components/gh-member-avatar.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{this.initials}}
4 |
5 | {{#if this.avatarImage}}
6 |
7 | {{/if}}
8 |
9 |
--------------------------------------------------------------------------------
/app/components/gh-member-details.js:
--------------------------------------------------------------------------------
1 | import Component from '@glimmer/component';
2 | import {inject as service} from '@ember/service';
3 |
4 | export default class extends Component {
5 | @service settings;
6 | }
--------------------------------------------------------------------------------
/app/components/gh-member-single-label-input.hbs:
--------------------------------------------------------------------------------
1 |
2 |
9 | {{svg-jar "arrow-down-small"}}
10 |
11 |
--------------------------------------------------------------------------------
/app/components/gh-members-filter-count.hbs:
--------------------------------------------------------------------------------
1 | {{this.memberCount}}
--------------------------------------------------------------------------------
/app/components/gh-members-segment-count.hbs:
--------------------------------------------------------------------------------
1 | {{#if this.session.user.isAdmin}}
2 |
7 | {{format-number this.segmentTotal}} {{gh-pluralize this.segmentTotal "member" without-count=true}}
8 |
9 | {{/if}}
--------------------------------------------------------------------------------
/app/components/gh-mobile-nav-bar.js:
--------------------------------------------------------------------------------
1 | import Component from '@ember/component';
2 | import classic from 'ember-classic-decorator';
3 | import {classNames, tagName} from '@ember-decorators/component';
4 | import {inject as service} from '@ember/service';
5 |
6 | @classic
7 | @tagName('nav')
8 | @classNames('gh-mobile-nav-bar')
9 | export default class GhMobileNavBar extends Component {
10 | @service ui;
11 | }
12 |
--------------------------------------------------------------------------------
/app/components/gh-nav-menu.hbs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/components/gh-notifications.hbs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/components/gh-notifications.js:
--------------------------------------------------------------------------------
1 | import Component from '@glimmer/component';
2 | import {inject as service} from '@ember/service';
3 |
4 | export default class GhNotifications extends Component {
5 | @service notifications;
6 | }
7 |
--------------------------------------------------------------------------------
/app/components/gh-progress-bar.hbs:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/app/components/gh-psm-authors-input.hbs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/components/gh-psm-tags-input.hbs:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/app/components/gh-psm-visibility-input.hbs:
--------------------------------------------------------------------------------
1 |
2 |
9 | {{svg-jar "arrow-down-small"}}
10 |
--------------------------------------------------------------------------------
/app/components/gh-recipient-filter-count.hbs:
--------------------------------------------------------------------------------
1 | {{#if @filter}}
2 |
3 | {{else}}
4 | 0 members
5 | {{/if}}
6 |
--------------------------------------------------------------------------------
/app/components/gh-scroll-trigger.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{yield}}
3 |
--------------------------------------------------------------------------------
/app/components/gh-simplemde.hbs:
--------------------------------------------------------------------------------
1 | {{yield}}
2 |
--------------------------------------------------------------------------------
/app/components/gh-site-iframe.hbs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/components/gh-text-input.hbs:
--------------------------------------------------------------------------------
1 | {{yield}}
--------------------------------------------------------------------------------
/app/components/gh-text-input.js:
--------------------------------------------------------------------------------
1 | import TextField from '@ember/component/text-field';
2 | import TextInputMixin from 'ghost-admin/mixins/text-input';
3 | import classic from 'ember-classic-decorator';
4 | import {classNames} from '@ember-decorators/component';
5 |
6 | @classic
7 | @classNames('gh-input')
8 | export default class GhTextInput extends TextField.extend(TextInputMixin) {}
9 |
--------------------------------------------------------------------------------
/app/components/gh-theme-error-li.js:
--------------------------------------------------------------------------------
1 | import Component from '@ember/component';
2 | import classic from 'ember-classic-decorator';
3 | import {action} from '@ember/object';
4 | import {tagName} from '@ember-decorators/component';
5 |
6 | @classic
7 | @tagName('')
8 | export default class GhThemeErrorLi extends Component {
9 | error = null;
10 | showDetails = false;
11 |
12 | @action
13 | toggleDetails() {
14 | this.toggleProperty('showDetails');
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/components/gh-token-input/label-selected-item.hbs:
--------------------------------------------------------------------------------
1 | {{@option.name}}
2 |
--------------------------------------------------------------------------------
/app/components/gh-token-input/label-token.hbs:
--------------------------------------------------------------------------------
1 | {{yield}}
2 |
--------------------------------------------------------------------------------
/app/components/gh-token-input/label-token.js:
--------------------------------------------------------------------------------
1 | import DraggableObject from 'ember-drag-drop/components/draggable-object';
2 | import classic from 'ember-classic-decorator';
3 | import {attributeBindings, classNames} from '@ember-decorators/component';
4 |
5 | @classic
6 | @attributeBindings('title')
7 | @classNames('label-token')
8 | export default class LabelToken extends DraggableObject {
9 | title = 'Label';
10 | }
11 |
--------------------------------------------------------------------------------
/app/components/gh-token-input/suggested-option.hbs:
--------------------------------------------------------------------------------
1 | {{@option.text}}
2 |
--------------------------------------------------------------------------------
/app/components/gh-token-input/tag-token.hbs:
--------------------------------------------------------------------------------
1 | {{yield}}
2 |
--------------------------------------------------------------------------------
/app/components/gh-url-input.hbs:
--------------------------------------------------------------------------------
1 |
9 |
10 |
--------------------------------------------------------------------------------
/app/components/gh-url-preview.hbs:
--------------------------------------------------------------------------------
1 | {{this.url}}
2 |
--------------------------------------------------------------------------------
/app/components/gh-user-active.hbs:
--------------------------------------------------------------------------------
1 | {{yield this}}
2 |
--------------------------------------------------------------------------------
/app/components/gh-user-invited.hbs:
--------------------------------------------------------------------------------
1 | {{yield this}}
2 |
--------------------------------------------------------------------------------
/app/components/gh-user-list-item.js:
--------------------------------------------------------------------------------
1 | import Component from '@ember/component';
2 | import classic from 'ember-classic-decorator';
3 | import {tagName} from '@ember-decorators/component';
4 |
5 | @classic
6 | @tagName('')
7 | export default class GhUserListItem extends Component {}
8 |
--------------------------------------------------------------------------------
/app/components/gh-view-title.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{yield}}
3 |
--------------------------------------------------------------------------------
/app/components/gh-view-title.js:
--------------------------------------------------------------------------------
1 | import Component from '@ember/component';
2 | import classic from 'ember-classic-decorator';
3 | import {classNames, tagName} from '@ember-decorators/component';
4 | import {inject as service} from '@ember/service';
5 |
6 | @classic
7 | @tagName('h2')
8 | @classNames('view-title')
9 | export default class GhViewTitle extends Component {
10 | @service ui;
11 | }
12 |
--------------------------------------------------------------------------------
/app/components/inputs/select.hbs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/components/inputs/select/option.hbs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/components/koenig-react-editor.hbs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/components/liquid-container.js:
--------------------------------------------------------------------------------
1 | import LiquidContainer from 'liquid-fire/components/liquid-container';
2 | import config from 'ghost-admin/config/environment';
3 |
4 | export default LiquidContainer.extend({
5 | init() {
6 | this._super(...arguments);
7 |
8 | if (config.environment === 'test') {
9 | this.growDuration = 5;
10 | }
11 | }
12 | });
13 |
--------------------------------------------------------------------------------
/app/components/member/activity-feed-empty.hbs:
--------------------------------------------------------------------------------
1 |
2 |
{{svg-jar "no-data-list"}}
3 |
Activity
4 |
5 | All events related to this member will be shown here.
6 |
7 |
--------------------------------------------------------------------------------
/app/components/members-activity/member-filter-trigger.hbs:
--------------------------------------------------------------------------------
1 | Filter member {{svg-jar "arrow-down-small"}}
2 |
--------------------------------------------------------------------------------
/app/components/modal-early-access.js:
--------------------------------------------------------------------------------
1 | import ModalComponent from 'ghost-admin/components/modal-base';
2 |
3 | export default ModalComponent.extend({});
4 |
--------------------------------------------------------------------------------
/app/components/modal-leave-settings.js:
--------------------------------------------------------------------------------
1 | import ModalComponent from 'ghost-admin/components/modal-base';
2 | import RSVP from 'rsvp';
3 |
4 | export default ModalComponent.extend({
5 | actions: {
6 | confirm() {
7 | this.confirm();
8 | this.send('closeModal');
9 | }
10 | },
11 |
12 | // Allowed actions
13 | confirm: () => RSVP.resolve()
14 | });
15 |
--------------------------------------------------------------------------------
/app/components/modal-markdown-help.js:
--------------------------------------------------------------------------------
1 | import ModalComponent from 'ghost-admin/components/modal-base';
2 |
3 | export default ModalComponent.extend({
4 | actions: {
5 | // noop - we don't want the enter key doing anything
6 | confirm() {}
7 | }
8 | });
9 |
--------------------------------------------------------------------------------
/app/components/modal-regenerate-token.js:
--------------------------------------------------------------------------------
1 | import ModalComponent from 'ghost-admin/components/modal-base';
2 |
3 | export default ModalComponent.extend({
4 | actions: {
5 | confirm() {
6 | this.confirm();
7 | this.send('closeModal');
8 | }
9 | }
10 | });
11 |
--------------------------------------------------------------------------------
/app/components/modal-upgrade-unsuspend-user-host-limit.js:
--------------------------------------------------------------------------------
1 | import ModalComponent from 'ghost-admin/components/modal-base';
2 | import {inject as service} from '@ember/service';
3 |
4 | export default ModalComponent.extend({
5 | router: service(),
6 |
7 | actions: {
8 | upgrade() {
9 | this.router.transitionTo('pro');
10 | },
11 |
12 | confirm() {
13 | this.send('upgrade');
14 | }
15 | }
16 | });
17 |
--------------------------------------------------------------------------------
/app/components/modal-whats-new.js:
--------------------------------------------------------------------------------
1 | import ModalComponent from 'ghost-admin/components/modal-base';
2 | import {inject as service} from '@ember/service';
3 |
4 | export default ModalComponent.extend({
5 | whatsNew: service(),
6 |
7 | confirm() {},
8 |
9 | actions: {
10 | // noop - enter key shouldn't do anything
11 | confirm() {}
12 | }
13 | });
14 |
--------------------------------------------------------------------------------
/app/components/modals/search.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Open with Ctrl/⌘ + K
5 |
6 |
--------------------------------------------------------------------------------
/app/components/modals/search.js:
--------------------------------------------------------------------------------
1 | import Component from '@glimmer/component';
2 | import {action} from '@ember/object';
3 |
4 | export default class SearchModal extends Component {
5 | @action
6 | focusFirstInput(mouseEvent) {
7 | mouseEvent.target.querySelector('input')?.focus();
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/app/components/power-select-vertical-collection-options.js:
--------------------------------------------------------------------------------
1 | import OptionsComponent from 'ember-power-select/components/power-select/options';
2 |
3 | export default class PowerSelectVerticalCollectionOptions extends OptionsComponent {}
4 |
--------------------------------------------------------------------------------
/app/components/react-component.hbs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/components/settings/members/archive-tier.hbs:
--------------------------------------------------------------------------------
1 | {{#if this.tier.active}}
2 | {{#unless this.tier.isNew}}
3 |
9 | {{/unless}}
10 | {{else}}
11 |
17 | {{/if}}
--------------------------------------------------------------------------------
/app/controllers/billing.js:
--------------------------------------------------------------------------------
1 | import Controller from '@ember/controller';
2 | import classic from 'ember-classic-decorator';
3 | import {alias} from '@ember/object/computed';
4 |
5 | @classic
6 | export default class BillingController extends Controller {
7 | queryParams = ['action'];
8 | action = null;
9 |
10 | @alias('model')
11 | guid;
12 | }
13 |
--------------------------------------------------------------------------------
/app/controllers/designsandbox.js:
--------------------------------------------------------------------------------
1 | import Controller from '@ember/controller';
2 |
3 | export default class DesignsandboxController extends Controller {
4 | }
--------------------------------------------------------------------------------
/app/controllers/editor/edit-loading.js:
--------------------------------------------------------------------------------
1 | import Controller from '@ember/controller';
2 | import {inject as service} from '@ember/service';
3 | export default class EditLoadingController extends Controller {
4 | @service ui;
5 | }
6 |
--------------------------------------------------------------------------------
/app/controllers/home.js:
--------------------------------------------------------------------------------
1 | import Controller from '@ember/controller';
2 | import {tracked} from '@glimmer/tracking';
3 |
4 | export default class HomeController extends Controller {
5 | queryParams = ['firstStart'];
6 |
7 | @tracked firstStart = null;
8 | }
9 |
--------------------------------------------------------------------------------
/app/controllers/pages-loading.js:
--------------------------------------------------------------------------------
1 | import PostsLoadingController from './posts-loading';
2 | import classic from 'ember-classic-decorator';
3 | import {inject as controller} from '@ember/controller';
4 | import {inject as service} from '@ember/service';
5 |
6 | /* eslint-disable ghost/ember/alias-model-in-controller */
7 | @classic
8 | export default class PagesLoadingController extends PostsLoadingController {
9 | @controller('pages')
10 | postsController;
11 |
12 | @service ui;
13 | }
14 |
--------------------------------------------------------------------------------
/app/controllers/react-editor/edit-loading.js:
--------------------------------------------------------------------------------
1 | import Controller from '@ember/controller';
2 | import {inject as service} from '@ember/service';
3 | export default class ReactEditLoadingController extends Controller {
4 | @service ui;
5 | }
6 |
--------------------------------------------------------------------------------
/app/controllers/settings/design.js:
--------------------------------------------------------------------------------
1 | import Controller from '@ember/controller';
2 |
3 | export default class SettingsDesignController extends Controller {
4 | }
5 |
--------------------------------------------------------------------------------
/app/controllers/settings/design/change-theme/install.js:
--------------------------------------------------------------------------------
1 | import Controller from '@ember/controller';
2 | import {tracked} from '@glimmer/tracking';
3 |
4 | export default class InstallThemeController extends Controller {
5 | queryParams = ['source', 'ref'];
6 |
7 | @tracked source = '';
8 | @tracked ref = '';
9 | }
10 |
--------------------------------------------------------------------------------
/app/controllers/settings/staff/user-loading.js:
--------------------------------------------------------------------------------
1 | import Controller from '@ember/controller';
2 | import {inject as service} from '@ember/service';
3 |
4 | export default class StaffUserLoadingController extends Controller {
5 | @service session;
6 | }
--------------------------------------------------------------------------------
/app/controllers/site.js:
--------------------------------------------------------------------------------
1 | import Controller from '@ember/controller';
2 | import classic from 'ember-classic-decorator';
3 | import {alias} from '@ember/object/computed';
4 |
5 | @classic
6 | export default class SiteController extends Controller {
7 | @alias('model')
8 | guid;
9 | }
10 |
--------------------------------------------------------------------------------
/app/errors/email-failed-error.js:
--------------------------------------------------------------------------------
1 | export default class EmailFailedError extends Error {
2 | constructor(message) {
3 | super(message);
4 | this.name = 'EmailFailedError';
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/app/errors/member-import-error.js:
--------------------------------------------------------------------------------
1 | export default class EmailFailedError extends Error {
2 | constructor({message, context, type = 'error'}) {
3 | super(message);
4 | this.name = 'MemberImportError';
5 | this.context = context;
6 | this.type = type;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/app/helpers/accent-color-background.js:
--------------------------------------------------------------------------------
1 | import Helper from '@ember/component/helper';
2 | import classic from 'ember-classic-decorator';
3 | import {htmlSafe} from '@ember/template';
4 | import {inject as service} from '@ember/service';
5 |
6 | @classic
7 | export default class AccentColorBackgroundHelper extends Helper {
8 | @service config;
9 |
10 | compute() {
11 | const color = this.get('config.accent_color');
12 | return htmlSafe(`background: ${color};`);
13 | }
14 | }
--------------------------------------------------------------------------------
/app/helpers/author-names.js:
--------------------------------------------------------------------------------
1 | import {helper} from '@ember/component/helper';
2 | import {isEmpty} from '@ember/utils';
3 |
4 | export function authorNames([authors]/*, hash*/) {
5 | if (!authors || isEmpty(authors)) {
6 | return;
7 | }
8 |
9 | return authors.mapBy('name').join(', ');
10 | }
11 |
12 | export default helper(authorNames);
13 |
--------------------------------------------------------------------------------
/app/helpers/background-image-style.js:
--------------------------------------------------------------------------------
1 | import {helper} from '@ember/component/helper';
2 | import {htmlSafe} from '@ember/template';
3 |
4 | export function backgroundImageStyle([url]/*, hash*/) {
5 | if (url) {
6 | let safeUrl = encodeURI(decodeURI(url));
7 | return htmlSafe(`background-image: url(${safeUrl});`);
8 | }
9 |
10 | return '';
11 | }
12 |
13 | export default helper(backgroundImageStyle);
14 |
--------------------------------------------------------------------------------
/app/helpers/capitalize-first-letter.js:
--------------------------------------------------------------------------------
1 | import {helper} from '@ember/component/helper';
2 |
3 | export function capitalizeFirstLetter(string) {
4 | if (typeof string !== 'string' || string.length === 0) {
5 | return string;
6 | }
7 | return string.charAt(0).toUpperCase() + string.slice(1);
8 | }
9 |
10 | export default helper(([string]) => capitalizeFirstLetter(string));
11 |
--------------------------------------------------------------------------------
/app/helpers/currency-symbol.js:
--------------------------------------------------------------------------------
1 | import Helper from '@ember/component/helper';
2 | import {getSymbol} from 'ghost-admin/utils/currency';
3 | import {inject as service} from '@ember/service';
4 |
5 | export default class CurrencySymbolHelper extends Helper {
6 | @service feature;
7 |
8 | compute([currency]) {
9 | if (currency) {
10 | return getSymbol(currency);
11 | }
12 | return '';
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/helpers/enable-developer-experiments.js:
--------------------------------------------------------------------------------
1 | import Helper from '@ember/component/helper';
2 | import {inject as service} from '@ember/service';
3 |
4 | export default class EnableDeveloperExperimentsHelper extends Helper {
5 | @service config;
6 |
7 | compute() {
8 | return this.config.get('enableDeveloperExperiments');
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/app/helpers/feature.js:
--------------------------------------------------------------------------------
1 | import Helper from '@ember/component/helper';
2 | import {inject as service} from '@ember/service';
3 |
4 | export default class EnableDeveloperExperimentsHelper extends Helper {
5 | @service feature;
6 |
7 | compute([featureFlag]) {
8 | return this.feature.get(featureFlag);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/app/helpers/first-name.js:
--------------------------------------------------------------------------------
1 | import {helper} from '@ember/component/helper';
2 |
3 | export function firstName([name = '']) {
4 | return name.split(' ')[0];
5 | }
6 |
7 | export default helper(firstName);
--------------------------------------------------------------------------------
/app/helpers/format-number.js:
--------------------------------------------------------------------------------
1 | import {helper} from '@ember/component/helper';
2 |
3 | export function formatNumber(number, options) {
4 | if (number === '' || number === null || number === undefined) {
5 | return;
6 | }
7 |
8 | return Number(number).toLocaleString(undefined, options);
9 | }
10 |
11 | export default helper(function ([number]/*, hash*/) {
12 | return formatNumber(number);
13 | });
14 |
--------------------------------------------------------------------------------
/app/helpers/full-email-address.js:
--------------------------------------------------------------------------------
1 | import Helper from '@ember/component/helper';
2 | import {inject as service} from '@ember/service';
3 |
4 | export default class FullEmailAddressHelper extends Helper {
5 | @service config;
6 |
7 | compute([email = '']) {
8 | if (email.indexOf('@') > -1) {
9 | return email;
10 | }
11 |
12 | return `${email}@${this.config.emailDomain}`;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/helpers/get-setting.js:
--------------------------------------------------------------------------------
1 | import Helper from '@ember/component/helper';
2 | import {get} from '@ember/object';
3 | import {inject as service} from '@ember/service';
4 |
5 | export default class GetSetting extends Helper {
6 | @service settings;
7 |
8 | compute([key = '']) {
9 | return get(this.settings, key);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/app/helpers/hex-contrast.js:
--------------------------------------------------------------------------------
1 | import {Color, textColorForBackgroundColor} from '@tryghost/color-utils';
2 | import {helper} from '@ember/component/helper';
3 |
4 | export default helper(function hexContrast([hex]) {
5 | return textColorForBackgroundColor(Color(hex)).hex();
6 | });
7 |
--------------------------------------------------------------------------------
/app/helpers/highlighted-text.js:
--------------------------------------------------------------------------------
1 | import {helper} from '@ember/component/helper';
2 | import {htmlSafe} from '@ember/template';
3 |
4 | export function highlightedText([text, termToHighlight]) {
5 | // replace any non-word character with an escaped character
6 | let sanitisedTerm = termToHighlight.replace(new RegExp(/\W/ig), '\\$&');
7 |
8 | return htmlSafe(text.replace(new RegExp(sanitisedTerm, 'ig'), '$&'));
9 | }
10 |
11 | export default helper(highlightedText);
12 |
--------------------------------------------------------------------------------
/app/helpers/integration-icon-style.js:
--------------------------------------------------------------------------------
1 | import {helper} from '@ember/component/helper';
2 | import {htmlSafe} from '@ember/template';
3 |
4 | export function integrationLogoStyle([integration]/*, hash*/) {
5 | if (integration.iconImage) {
6 | let style = `background-image:url(${integration.iconImage});background-size:36px;`;
7 | return htmlSafe(style);
8 | }
9 | }
10 |
11 | export default helper(integrationLogoStyle);
12 |
--------------------------------------------------------------------------------
/app/helpers/is-moment-today.js:
--------------------------------------------------------------------------------
1 | import Helper from '@ember/component/helper';
2 | import moment from 'moment';
3 | import {inject as service} from '@ember/service';
4 |
5 | export default class IsMomentToday extends Helper {
6 | @service settings;
7 |
8 | compute([date]) {
9 | const today = moment().tz(this.settings.get('timezone'));
10 | const dateMoment = moment.tz(date, this.settings.get('timezone'));
11 |
12 | return dateMoment.isSame(today, 'day');
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/helpers/moment-site-tz.js:
--------------------------------------------------------------------------------
1 | import Helper from '@ember/component/helper';
2 | import moment from 'moment';
3 | import {inject as service} from '@ember/service';
4 |
5 | export default class MomentSiteTz extends Helper {
6 | @service settings;
7 |
8 | compute([date]) {
9 | return moment.tz(date, this.settings.get('timezone'));
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/app/helpers/noop.js:
--------------------------------------------------------------------------------
1 | import {helper} from '@ember/component/helper';
2 |
3 | export default helper(function noop() {
4 | return () => {};
5 | });
6 |
--------------------------------------------------------------------------------
/app/helpers/post-author-names.js:
--------------------------------------------------------------------------------
1 | import {helper} from '@ember/component/helper';
2 |
3 | export default helper(function postAuthorNames([post]/*, hash*/) {
4 | return (post?.authors || []).map(author => author.name || author.email).join(', ');
5 | });
6 |
--------------------------------------------------------------------------------
/app/helpers/query-selector.js:
--------------------------------------------------------------------------------
1 | export default function (selector) {
2 | const elem = document.querySelector(selector);
3 |
4 | if (!elem) {
5 | console.warn(`{{query-selector}} could not find an element matching "${selector}"`); //eslint-disable-line
6 | }
7 |
8 | return elem;
9 | }
10 |
--------------------------------------------------------------------------------
/app/helpers/set-has.js:
--------------------------------------------------------------------------------
1 | import {helper} from '@ember/component/helper';
2 |
3 | export default helper(function ([set, key]) {
4 | return set.has(key);
5 | });
6 |
--------------------------------------------------------------------------------
/app/helpers/site-icon-style.js:
--------------------------------------------------------------------------------
1 | import Helper from '@ember/component/helper';
2 | import classic from 'ember-classic-decorator';
3 | import {htmlSafe} from '@ember/template';
4 | import {inject as service} from '@ember/service';
5 |
6 | @classic
7 | export default class SiteIconStyleHelper extends Helper {
8 | @service config;
9 |
10 | compute() {
11 | const icon = this.get('config.icon') || 'https://static.ghost.org/v4.0.0/images/ghost-orb-2.png';
12 | return htmlSafe(`background-image: url(${icon})`);
13 | }
14 | }
--------------------------------------------------------------------------------
/app/helpers/toggle-feature.js:
--------------------------------------------------------------------------------
1 | import Helper from '@ember/component/helper';
2 | import {inject as service} from '@ember/service';
3 |
4 | export default class ToggleFeature extends Helper {
5 | @service feature;
6 |
7 | compute([featureFlag]) {
8 | return () => {
9 | const flag = !!this.feature.get(featureFlag);
10 | this.feature.set(featureFlag, !flag);
11 | };
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app/helpers/ui-btn-span.js:
--------------------------------------------------------------------------------
1 | import {btnStyles} from './ui-btn';
2 | import {helper} from '@ember/component/helper';
3 |
4 | export function uiBtnSpan([style], hash) {
5 | return btnStyles(Object.assign({}, {style}, hash)).span;
6 | }
7 |
8 | export default helper(uiBtnSpan);
9 |
--------------------------------------------------------------------------------
/app/initializers/upgrade-status.js:
--------------------------------------------------------------------------------
1 | export function initialize(application) {
2 | application.inject('route', 'upgradeStatus', 'service:upgrade-status');
3 | }
4 |
5 | export default {
6 | name: 'upgrade-status',
7 | initialize
8 | };
9 |
--------------------------------------------------------------------------------
/app/mixins/dropdown-mixin.js:
--------------------------------------------------------------------------------
1 | import Evented from '@ember/object/evented';
2 | import Mixin from '@ember/object/mixin';
3 |
4 | /*
5 | Dropdowns and their buttons are evented and do not propagate clicks.
6 | */
7 | export default Mixin.create(Evented, {
8 | classNameBindings: ['isOpen:open:closed'],
9 | isOpen: false,
10 |
11 | click(event) {
12 | this._super(event);
13 |
14 | return event.stopPropagation();
15 | }
16 | });
17 |
--------------------------------------------------------------------------------
/app/models/action.js:
--------------------------------------------------------------------------------
1 | import Model, {attr} from '@ember-data/model';
2 |
3 | export default Model.extend({
4 | resourceId: attr('string'),
5 | resourceType: attr('string'),
6 | actorId: attr('string'),
7 | actorType: attr('string'),
8 | event: attr('string'),
9 | context: attr('json-string'),
10 | createdAtUTC: attr('moment-utc')
11 | });
12 |
--------------------------------------------------------------------------------
/app/models/api-key.js:
--------------------------------------------------------------------------------
1 | import Model, {attr, belongsTo} from '@ember-data/model';
2 |
3 | export default Model.extend({
4 | type: attr('string'),
5 | secret: attr('string'),
6 | lastSeenAtUTC: attr('moment-utc'),
7 | createdAtUTC: attr('moment-utc'),
8 | createdBy: attr('number'),
9 | updatedAtUTC: attr('moment-utc'),
10 | updatedBy: attr('number'),
11 |
12 | integration: belongsTo('integration')
13 | });
14 |
--------------------------------------------------------------------------------
/app/models/custom-theme-setting-list.js:
--------------------------------------------------------------------------------
1 | import Model, {hasMany} from '@ember-data/model';
2 |
3 | export default Model.extend({
4 | customThemeSettings: hasMany('custom-theme-setting')
5 | });
6 |
--------------------------------------------------------------------------------
/app/models/custom-theme-setting.js:
--------------------------------------------------------------------------------
1 | import Model, {attr} from '@ember-data/model';
2 |
3 | export default Model.extend({
4 | key: attr('string'),
5 | type: attr('string'),
6 | options: attr(),
7 | default: attr('string'),
8 | value: attr(),
9 | group: attr('string')
10 | });
11 |
--------------------------------------------------------------------------------
/app/models/member-tier.js:
--------------------------------------------------------------------------------
1 | import EmberObject from '@ember/object';
2 |
3 | export default EmberObject.extend({
4 | name: 'Name of the tier',
5 | slug: 'Slug for the tier'
6 | });
7 |
--------------------------------------------------------------------------------
/app/models/notification.js:
--------------------------------------------------------------------------------
1 | import Model, {attr} from '@ember-data/model';
2 |
3 | export default Model.extend({
4 | custom: attr('boolean'),
5 | dismissible: attr('boolean'),
6 | key: attr('string'),
7 | message: attr('string'),
8 | status: attr('string'),
9 | type: attr('string')
10 | });
11 |
--------------------------------------------------------------------------------
/app/models/page.js:
--------------------------------------------------------------------------------
1 | import PostModel from './post';
2 |
3 | export default PostModel.extend({
4 | displayName: 'page'
5 | });
6 |
--------------------------------------------------------------------------------
/app/models/role.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable camelcase */
2 | import Model, {attr} from '@ember-data/model';
3 | import {computed} from '@ember/object';
4 |
5 | export default Model.extend({
6 | name: attr('string'),
7 | description: attr('string'),
8 | createdAtUTC: attr('moment-utc'),
9 | updatedAtUTC: attr('moment-utc'),
10 | createdBy: attr('number'),
11 | updatedBy: attr('number'),
12 |
13 | lowerCaseName: computed('name', function () {
14 | return (this.name || '').toLocaleLowerCase();
15 | })
16 | });
17 |
--------------------------------------------------------------------------------
/app/models/snippet.js:
--------------------------------------------------------------------------------
1 | import Model, {attr} from '@ember-data/model';
2 | import ValidationEngine from 'ghost-admin/mixins/validation-engine';
3 |
4 | export default Model.extend(ValidationEngine, {
5 | validationType: 'snippet',
6 |
7 | name: attr('string'),
8 | mobiledoc: attr('json-string'),
9 | createdAtUTC: attr('moment-utc'),
10 | updatedAtUTC: attr('moment-utc')
11 | });
12 |
--------------------------------------------------------------------------------
/app/modifiers/autofocus.js:
--------------------------------------------------------------------------------
1 | import {modifier} from 'ember-modifier';
2 |
3 | export default modifier(element => element.focus(), {eager: false});
4 |
--------------------------------------------------------------------------------
/app/modifiers/scroll-top.js:
--------------------------------------------------------------------------------
1 | import getScrollParent from 'ghost-admin/utils/get-scroll-parent';
2 | import {modifier} from 'ember-modifier';
3 |
4 | export default modifier((element) => {
5 | getScrollParent(element).scrollTop = 0;
6 | }, {eager: false});
7 |
--------------------------------------------------------------------------------
/app/routes/admin.js:
--------------------------------------------------------------------------------
1 | import AuthenticatedRoute from './authenticated';
2 | import {inject as service} from '@ember/service';
3 |
4 | export default class AdminRoute extends AuthenticatedRoute {
5 | @service session;
6 |
7 | beforeModel() {
8 | super.beforeModel(...arguments);
9 |
10 | if (!this.session.user.isAdmin) {
11 | return this.transitionTo('home');
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/routes/authenticated.js:
--------------------------------------------------------------------------------
1 | import Route from '@ember/routing/route';
2 | import {inject as service} from '@ember/service';
3 |
4 | export default class AuthenticatedRoute extends Route {
5 | @service session;
6 |
7 | beforeModel(transition) {
8 | this.session.requireAuthentication(transition, 'signin');
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/app/routes/editor/index.js:
--------------------------------------------------------------------------------
1 | import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
2 |
3 | export default class IndexRoute extends AuthenticatedRoute {
4 | beforeModel() {
5 | super.beforeModel(...arguments);
6 | this.replaceWith('editor.new', 'post');
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/app/routes/error404.js:
--------------------------------------------------------------------------------
1 | import Route from '@ember/routing/route';
2 |
3 | export default class Error404Route extends Route {
4 | controllerName = 'error';
5 | templateName = 'error';
6 |
7 | model() {
8 | return {
9 | status: 404
10 | };
11 | }
12 |
13 | buildRouteInfoMetadata() {
14 | return {
15 | titleToken: 'Error'
16 | };
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/routes/launch.js:
--------------------------------------------------------------------------------
1 | import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
2 | import {inject as service} from '@ember/service';
3 |
4 | export default class LaunchRoute extends AuthenticatedRoute {
5 | @service session;
6 |
7 | beforeModel() {
8 | super.beforeModel(...arguments);
9 | if (!this.session.user.isOwnerOnly) {
10 | return this.transitionTo('home');
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app/routes/member/new.js:
--------------------------------------------------------------------------------
1 | import MemberRoute from '../member';
2 |
3 | export default class NewMemberRoute extends MemberRoute {
4 | controllerName = 'member';
5 | templateName = 'member';
6 | }
7 |
--------------------------------------------------------------------------------
/app/routes/members-activity.js:
--------------------------------------------------------------------------------
1 | import AdminRoute from 'ghost-admin/routes/admin';
2 |
3 | export default class MembersActivityRoute extends AdminRoute {
4 | }
5 |
--------------------------------------------------------------------------------
/app/routes/members/import.js:
--------------------------------------------------------------------------------
1 | import AdminRoute from 'ghost-admin/routes/admin';
2 |
3 | export default class MembersImportRoute extends AdminRoute {}
4 |
--------------------------------------------------------------------------------
/app/routes/offer/new.js:
--------------------------------------------------------------------------------
1 | import OfferRoute from '../offer';
2 |
3 | export default class NewOfferRoute extends OfferRoute {
4 | controllerName = 'offer';
5 | templateName = 'offer';
6 | }
7 |
--------------------------------------------------------------------------------
/app/routes/pages.js:
--------------------------------------------------------------------------------
1 | import PostsRoute from './posts';
2 |
3 | export default class PagesRoute extends PostsRoute {
4 | modelName = 'page';
5 |
6 | buildRouteInfoMetadata() {
7 | return {
8 | titleToken: 'Pages'
9 | };
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/app/routes/react-editor/index.js:
--------------------------------------------------------------------------------
1 | import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
2 |
3 | export default class IndexRoute extends AuthenticatedRoute {
4 | beforeModel() {
5 | super.beforeModel(...arguments);
6 | this.replaceWith('react-editor.new', 'post');
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/app/routes/settings.js:
--------------------------------------------------------------------------------
1 | import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
2 | import {inject as service} from '@ember/service';
3 |
4 | export default class SettingsRoute extends AuthenticatedRoute {
5 | @service session;
6 |
7 | beforeModel() {
8 | super.beforeModel(...arguments);
9 |
10 | const user = this.session.user;
11 |
12 | if (!user.isAdmin) {
13 | return this.transitionTo('settings.staff.user', user);
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/routes/settings/design/change-theme.js:
--------------------------------------------------------------------------------
1 | import AdminRoute from 'ghost-admin/routes/admin';
2 | import {action} from '@ember/object';
3 | import {inject as service} from '@ember/service';
4 |
5 | export default class ChangeThemeRoute extends AdminRoute {
6 | @service store;
7 |
8 | model() {
9 | return this.store.findAll('theme');
10 | }
11 |
12 | @action
13 | willTransition() {
14 | this.controllerFor('settings.design.change-theme').reset();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/routes/settings/integration/webhooks/edit.js:
--------------------------------------------------------------------------------
1 | import AdminRoute from 'ghost-admin/routes/admin';
2 |
3 | export default class EditRoute extends AdminRoute {
4 | model(params) {
5 | let integration = this.modelFor('settings.integration');
6 | let webhook = integration.webhooks.findBy('id', params.webhook_id);
7 | return webhook;
8 | }
9 |
10 | deactivate() {
11 | super.deactivate(...arguments);
12 | this.controller.reset();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/routes/settings/integration/webhooks/new.js:
--------------------------------------------------------------------------------
1 | import AdminRoute from 'ghost-admin/routes/admin';
2 |
3 | export default class NewRoute extends AdminRoute {
4 | model() {
5 | let integration = this.modelFor('settings.integration');
6 | return this.store.createRecord('webhook', {integration});
7 | }
8 |
9 | deactivate() {
10 | super.deactivate(...arguments);
11 | this.controller.webhook.rollbackAttributes();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app/routes/settings/members-email.js:
--------------------------------------------------------------------------------
1 | import AdminRoute from 'ghost-admin/routes/admin';
2 |
3 | export default class MembersEmailRoute extends AdminRoute {
4 | beforeModel() {
5 | // Moved to newsletters
6 | return this.replaceWith('settings.newsletters');
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/app/routes/settings/theme-install.js:
--------------------------------------------------------------------------------
1 | import Route from '@ember/routing/route';
2 |
3 | export default class InstallThemeRoute extends Route {
4 | redirect(model, transition) {
5 | this.transitionTo('settings.design.change-theme.install', {queryParams: transition.to.queryParams});
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/app/routes/settings/tier/new.js:
--------------------------------------------------------------------------------
1 | import TierRoute from '../tier';
2 |
3 | export default class NewTierRoute extends TierRoute {
4 | controllerName = 'settings.tier';
5 | templateName = 'settings.tier';
6 | }
7 |
--------------------------------------------------------------------------------
/app/routes/setup/index.js:
--------------------------------------------------------------------------------
1 | import Route from '@ember/routing/route';
2 |
3 | export default class IndexRoute extends Route {
4 | beforeModel() {
5 | super.beforeModel(...arguments);
6 | this.transitionTo('setup.one');
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/app/routes/signout.js:
--------------------------------------------------------------------------------
1 | import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
2 | import {inject as service} from '@ember/service';
3 |
4 | export default class SignoutRoute extends AuthenticatedRoute {
5 | @service notifications;
6 |
7 | afterModel/*model, transition*/() {
8 | this.notifications.clearAll();
9 | this.session.invalidate();
10 | }
11 |
12 | buildRouteInfoMetadata() {
13 | return {
14 | titleToken: 'Sign Out'
15 | };
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/routes/site.js:
--------------------------------------------------------------------------------
1 | import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
2 | import {inject as service} from '@ember/service';
3 |
4 | export default class SiteRoute extends AuthenticatedRoute {
5 | @service config;
6 | @service settings;
7 | @service ui;
8 |
9 | _hasLoggedIn = false;
10 |
11 | model() {
12 | return (new Date()).valueOf();
13 | }
14 |
15 | buildRouteInfoMetadata() {
16 | return {
17 | titleToken: 'Site'
18 | };
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/routes/tag/new.js:
--------------------------------------------------------------------------------
1 | import TagRoute from '../tag';
2 |
3 | export default class NewRoute extends TagRoute {
4 | controllerName = 'tag';
5 | templateName = 'tag';
6 | }
7 |
--------------------------------------------------------------------------------
/app/routes/whatsnew.js:
--------------------------------------------------------------------------------
1 | import AuthenticatedRoute from 'ghost-admin/routes/authenticated';
2 |
3 | export default class WhatsnewRoute extends AuthenticatedRoute {
4 | buildRouteInfoMetadata() {
5 | return {
6 | titleToken: `What's new?`
7 | };
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/app/serializers/action.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable camelcase */
2 | import ApplicationSerializer from 'ghost-admin/serializers/application';
3 |
4 | export default class ActionSerializer extends ApplicationSerializer {
5 | attrs = {
6 | createdAtUTC: {key: 'created_at'}
7 | };
8 | }
9 |
--------------------------------------------------------------------------------
/app/serializers/api-key.js:
--------------------------------------------------------------------------------
1 | import ApplicationSerializer from 'ghost-admin/serializers/application';
2 |
3 | export default class ApiKeySerializer extends ApplicationSerializer {
4 | attrs = {
5 | lastSeenAtUTC: {key: 'last_seen_at'},
6 | createdAtUTC: {key: 'created_at'},
7 | updatedAtUTC: {key: 'updated_at'}
8 | };
9 | }
10 |
--------------------------------------------------------------------------------
/app/serializers/email.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable camelcase */
2 | import ApplicationSerializer from 'ghost-admin/serializers/application';
3 |
4 | export default class EmailSerializer extends ApplicationSerializer {
5 | attrs = {
6 | createdAtUTC: {key: 'created_at'},
7 | updatedAtUTC: {key: 'updated_at'},
8 | submittedAtUTC: {key: 'submitted_at'}
9 | };
10 | }
11 |
--------------------------------------------------------------------------------
/app/serializers/integration.js:
--------------------------------------------------------------------------------
1 | import ApplicationSerializer from './application';
2 | import {EmbeddedRecordsMixin} from '@ember-data/serializer/rest';
3 |
4 | export default class IntegrationSerializer extends ApplicationSerializer.extend(EmbeddedRecordsMixin) {
5 | attrs = {
6 | apiKeys: {embedded: 'always'},
7 | webhooks: {embedded: 'always'},
8 | createdAtUTC: {key: 'created_at'},
9 | updatedAtUTC: {key: 'updated_at'}
10 | };
11 | }
12 |
--------------------------------------------------------------------------------
/app/serializers/invite.js:
--------------------------------------------------------------------------------
1 | import ApplicationSerializer from 'ghost-admin/serializers/application';
2 |
3 | export default class InviteSerializer extends ApplicationSerializer {
4 | attrs = {
5 | createdAtUTC: {key: 'created_at'},
6 | updatedAtUTC: {key: 'updated_at'}
7 | };
8 | }
9 |
--------------------------------------------------------------------------------
/app/serializers/notification.js:
--------------------------------------------------------------------------------
1 | import ApplicationSerializer from 'ghost-admin/serializers/application';
2 |
3 | export default class NotificationSerializer extends ApplicationSerializer {
4 | attrs = {
5 | key: {key: 'location'}
6 | };
7 | }
8 |
--------------------------------------------------------------------------------
/app/serializers/role.js:
--------------------------------------------------------------------------------
1 | import ApplicationSerializer from 'ghost-admin/serializers/application';
2 |
3 | export default class ActionSerializer extends ApplicationSerializer {
4 | attrs = {
5 | createdAtUTC: {key: 'created_at'},
6 | updatedAtUTC: {key: 'updated_at'}
7 | };
8 | }
9 |
--------------------------------------------------------------------------------
/app/serializers/theme.js:
--------------------------------------------------------------------------------
1 | import ApplicationSerializer from './application';
2 |
3 | export default class Theme extends ApplicationSerializer {
4 | primaryKey = 'name';
5 | }
6 |
--------------------------------------------------------------------------------
/app/serializers/tier.js:
--------------------------------------------------------------------------------
1 | import ApplicationSerializer from './application';
2 |
3 | export default class TierSerializer extends ApplicationSerializer {
4 | serialize() {
5 | let json = super.serialize(...arguments);
6 |
7 | if (json?.monthly_price) {
8 | json.monthly_price = Math.round(json.monthly_price);
9 | }
10 |
11 | if (json?.yearly_price) {
12 | json.yearly_price = Math.round(json.yearly_price);
13 | }
14 |
15 | return json;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/serializers/webhook.js:
--------------------------------------------------------------------------------
1 | import ApplicationSerializer from './application';
2 |
3 | export default class ActionSerializer extends ApplicationSerializer {
4 | attrs = {
5 | lastTriggeredAtUTC: {key: 'last_triggered_at'},
6 | createdAtUTC: {key: 'created_at'},
7 | updatedAtUTC: {key: 'updated_at'}
8 | };
9 | }
10 |
--------------------------------------------------------------------------------
/app/services/event-bus.js:
--------------------------------------------------------------------------------
1 | import Evented from '@ember/object/evented';
2 | import Service from '@ember/service';
3 | import classic from 'ember-classic-decorator';
4 |
5 | @classic
6 | export default class EventBusService extends Service.extend(Evented) {
7 | publish() {
8 | return this.trigger(...arguments);
9 | }
10 |
11 | subscribe() {
12 | return this.on(...arguments);
13 | }
14 |
15 | unsubscribe() {
16 | return this.off(...arguments);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/services/ghost-paths.js:
--------------------------------------------------------------------------------
1 | import Service from '@ember/service';
2 | import classic from 'ember-classic-decorator';
3 | import ghostPaths from 'ghost-admin/utils/ghost-paths';
4 |
5 | @classic
6 | export default class GhostPathsService extends Service.extend(ghostPaths()) {}
7 |
--------------------------------------------------------------------------------
/app/services/media.js:
--------------------------------------------------------------------------------
1 | import Service from '@ember/service';
2 | import classic from 'ember-classic-decorator';
3 |
4 | // dummy service to account for not having the ember-responsive dependency
5 | // available for ember-light-table (we don't use it so no need for the dep)
6 | // see https://github.com/offirgolan/ember-light-table/issues/576
7 | @classic
8 | export default class MediaService extends Service {}
9 |
--------------------------------------------------------------------------------
/app/services/utils.js:
--------------------------------------------------------------------------------
1 | import Service from '@ember/service';
2 |
3 | export default class UtilsService extends Service {
4 | downloadFile(url) {
5 | let iframe = document.getElementById('iframeDownload');
6 |
7 | if (!iframe) {
8 | iframe = document.createElement('iframe');
9 | iframe.id = 'iframeDownload';
10 | iframe.style.display = 'none';
11 | document.body.append(iframe);
12 | }
13 |
14 | iframe.setAttribute('src', url);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/styles/components/codemirror.css:
--------------------------------------------------------------------------------
1 | /* Exclude CodeMirror from the border-box reset to avoid scrollbar problems */
2 | .CodeMirror,
3 | .CodeMirror * {
4 | box-sizing: initial;
5 | }
6 |
7 | /* Re-apply CodeMirror's content-box styles overridden by above reset */
8 | .CodeMirror-scroll,
9 | .CodeMirror-sizer,
10 | .CodeMirror-gutter,
11 | .CodeMirror-gutters,
12 | .CodeMirror-linenumber {
13 | box-sizing: content-box;
14 | }
15 |
16 | .CodeMirror-linenumber {
17 | min-width: 14px;
18 | }
19 |
--------------------------------------------------------------------------------
/app/styles/components/stacks.css:
--------------------------------------------------------------------------------
1 | /* Lists that are open on the sides
2 | /* ------------------------------------------------- */
3 | .gh-stack {
4 | display: flex;
5 | flex-direction: column;
6 | }
7 |
8 | .gh-stack-item {
9 | margin-left: 0 !important;
10 | margin-right: 0 !important;
11 | padding-left: 0 !important;
12 | padding-right: 0 !important;
13 | }
14 |
15 | .gh-stack-item .gh-setting-content {
16 | margin-right: 24px;
17 | }
--------------------------------------------------------------------------------
/app/styles/spirit/_box-shadow.css:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | BOX-SHADOW
4 |
5 | Media Query Extensions:
6 | -ns = not-small
7 | -m = medium
8 | -l = large
9 |
10 | */
11 |
12 | .shadow-1 { box-shadow: var(--shadow-1); }
13 | .shadow-2 { box-shadow: var(--shadow-2); }
14 | .shadow-3 { box-shadow: var(--shadow-3); }
--------------------------------------------------------------------------------
/app/styles/spirit/_code.css:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | CODE
4 |
5 | */
6 |
7 | .pre {
8 | overflow-x: auto;
9 | overflow-y: hidden;
10 | overflow: scroll;
11 | }
12 |
--------------------------------------------------------------------------------
/app/styles/spirit/_colors.css:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | Ghost color variables
4 | Modifications use PostCSS color mod function: https://github.com/postcss/postcss-color-mod-function
5 |
6 | Note: unused, moved all colors to global.css. Long term we wanna get rid of Spirit
7 |
8 | */
9 |
--------------------------------------------------------------------------------
/app/styles/spirit/_custom-styles-dark.css:
--------------------------------------------------------------------------------
1 | .bg-grouped-table {
2 | background: #191b1f;
3 | }
4 |
5 | .highlight-whitegrey:hover {
6 | background-color: color-mod(var(--whitegrey) a(60%) s(+5%)) !important;
7 | }
--------------------------------------------------------------------------------
/app/styles/spirit/_debug-children.css:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | DEBUG CHILDREN
4 | Docs: http://tachyons.io/docs/debug/
5 |
6 | Just add the debug class to any element to see outlines on its
7 | children.
8 |
9 | */
10 |
11 | .debug * { outline: 1px solid gold; }
12 | .debug-white * { outline: 1px solid white; }
13 | .debug-black * { outline: 1px solid black; }
14 |
15 |
--------------------------------------------------------------------------------
/app/styles/spirit/_images.css:
--------------------------------------------------------------------------------
1 | /* Responsive images! */
2 |
3 | img { max-width: 100%; }
4 |
--------------------------------------------------------------------------------
/app/styles/spirit/_links.css:
--------------------------------------------------------------------------------
1 | .link {
2 | text-decoration: none;
3 | transition: color .15s ease-in;
4 | }
5 |
6 | .link:link,
7 | .link:visited {
8 | transition: color .15s ease-in;
9 | }
10 | .link:hover {
11 | transition: color .15s ease-in;
12 | }
13 | .link:active {
14 | transition: color .15s ease-in;
15 | }
16 | .link:focus {
17 | transition: color .15s ease-in;
18 | outline: 1px dotted currentColor;
19 | }
20 |
--------------------------------------------------------------------------------
/app/styles/spirit/_lists.css:
--------------------------------------------------------------------------------
1 | .list { list-style-type: none; }
2 |
--------------------------------------------------------------------------------
/app/styles/spirit/_module-template.css:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | MODULE NAME
4 |
5 | Use this scaffolding to create or extend your own modules with tachyons
6 | style architecture.
7 |
8 | */
9 |
10 |
11 | @media (--breakpoint-not-small) {
12 |
13 | }
14 |
15 | @media (--breakpoint-medium) {
16 |
17 | }
18 |
19 | @media (--breakpoint-large) {
20 |
21 | }
22 |
23 |
--------------------------------------------------------------------------------
/app/styles/spirit/_opacity.css:
--------------------------------------------------------------------------------
1 | .o-100 { opacity: 1; }
2 | .o-90 { opacity: .9; }
3 | .o-80 { opacity: .8; }
4 | .o-70 { opacity: .7; }
5 | .o-60 { opacity: .6; }
6 | .o-50 { opacity: .5; }
7 | .o-40 { opacity: .4; }
8 | .o-30 { opacity: .3; }
9 | .o-20 { opacity: .2; }
10 | .o-10 { opacity: .1; }
11 | .o-05 { opacity: .05; }
12 | .o-025 { opacity: .025; }
13 | .o-0 { opacity: 0; }
14 |
--------------------------------------------------------------------------------
/app/styles/spirit/_tables.css:
--------------------------------------------------------------------------------
1 | .collapse {
2 | border-collapse: collapse;
3 | border-spacing: 0;
4 | }
5 |
6 | .striped:nth-child(odd) {
7 | border-bottom: 1px solid var(--whitegrey);
8 | }
9 |
10 | .striped:nth-child(even) {
11 | background-color: var(--whitegrey-l2);
12 | border-bottom: 1px solid var(--whitegrey);
13 | }
14 |
15 | th, td {
16 | vertical-align: top;
17 | }
18 |
--------------------------------------------------------------------------------
/app/styles/spirit/spirit-dark.css:
--------------------------------------------------------------------------------
1 | @import "./spirit.css";
2 |
3 | /* Import dark theme overrides */
4 | @import "./_colors-dark.css";
5 | @import "./_custom-styles-dark.css";
6 |
--------------------------------------------------------------------------------
/app/templates/editor/edit-loading.hbs:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/app/templates/members/import.hbs:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/app/templates/react-editor/edit-loading.hbs:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/app/templates/settings/integration/webhooks/edit.hbs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/templates/settings/integration/webhooks/new.hbs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/templates/settings/labs-loading.hbs:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/templates/site.hbs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/templates/tags-loading.hbs:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/transforms/json-string.js:
--------------------------------------------------------------------------------
1 | import Transform from '@ember-data/serializer/transform';
2 |
3 | export default class JsonString extends Transform {
4 | deserialize(serialized) {
5 | let _serialized = serialized === '' ? null : serialized;
6 | return JSON.parse(_serialized);
7 | }
8 |
9 | serialize(deserialized) {
10 | return deserialized ? JSON.stringify(deserialized) : null;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/app/transforms/moment-date.js:
--------------------------------------------------------------------------------
1 | import Transform from '@ember-data/serializer/transform';
2 | import moment from 'moment';
3 |
4 | export default class MomentDate extends Transform {
5 | deserialize(serialized) {
6 | if (serialized) {
7 | return moment(serialized);
8 | }
9 | return serialized;
10 | }
11 |
12 | serialize(deserialized) {
13 | if (deserialized) {
14 | return moment(deserialized).toDate();
15 | }
16 | return deserialized;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/transforms/raw.js:
--------------------------------------------------------------------------------
1 | import Transform from '@ember-data/serializer/transform';
2 |
3 | export default class Raw extends Transform {
4 | deserialize(serialized) {
5 | return serialized;
6 | }
7 |
8 | serialize(deserialized) {
9 | return deserialized;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/app/utils/copy-text-to-clipboard.js:
--------------------------------------------------------------------------------
1 | export default function copyTextToClipboard(text) {
2 | navigator.clipboard.writeText(text);
3 | }
4 |
--------------------------------------------------------------------------------
/app/utils/ctrl-or-cmd.js:
--------------------------------------------------------------------------------
1 | export default navigator.userAgent.indexOf('Mac') !== -1 ? 'command' : 'ctrl';
2 |
--------------------------------------------------------------------------------
/app/utils/flatten-grouped-options.js:
--------------------------------------------------------------------------------
1 | export default function flattenGroupedOptions(options) {
2 | const flatOptions = [];
3 |
4 | function getOptions(option) {
5 | if (option.options) {
6 | return option.options.forEach(getOptions);
7 | }
8 |
9 | flatOptions.push(option);
10 | }
11 |
12 | options.forEach(getOptions);
13 |
14 | return flatOptions;
15 | }
16 |
--------------------------------------------------------------------------------
/app/utils/get-scroll-parent.js:
--------------------------------------------------------------------------------
1 | export default function getScrollParent(node) {
2 | const isElement = node instanceof HTMLElement;
3 | const overflowY = isElement && window.getComputedStyle(node).overflowY;
4 | const isScrollable = overflowY !== 'visible' && overflowY !== 'hidden';
5 |
6 | if (!node) {
7 | return null;
8 | } else if (isScrollable && node.scrollHeight >= node.clientHeight) {
9 | return node;
10 | }
11 |
12 | return getScrollParent(node.parentNode) || document.body;
13 | }
14 |
--------------------------------------------------------------------------------
/app/utils/isNumber.js:
--------------------------------------------------------------------------------
1 | // isNumber function from lodash
2 |
3 | const {toString} = Object.prototype;
4 |
5 | export default function (value) {
6 | return typeof value === 'number'
7 | || value
8 | && typeof value === 'object'
9 | && toString.call(value) === '[object Number]'
10 | || false;
11 | }
12 |
--------------------------------------------------------------------------------
/app/utils/slug-url.js:
--------------------------------------------------------------------------------
1 | import {isBlank} from '@ember/utils';
2 |
3 | export default function SlugUrl(url, query) {
4 | if (query && !isBlank(query.slug)) {
5 | url += `slug/${query.slug}/`;
6 | delete query.slug;
7 | }
8 |
9 | return url;
10 | }
11 |
--------------------------------------------------------------------------------
/app/utils/window-proxy.js:
--------------------------------------------------------------------------------
1 | export default {
2 | changeLocation(url) {
3 | window.location = url;
4 | },
5 |
6 | replaceLocation(url) {
7 | window.location.replace(url);
8 | },
9 |
10 | replaceState(params, title, url) {
11 | window.history.replaceState(params, title, url);
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/app/validators/custom-view.js:
--------------------------------------------------------------------------------
1 | import BaseValidator from './base';
2 | import {isBlank} from '@ember/utils';
3 |
4 | export default BaseValidator.create({
5 | properties: ['name'],
6 |
7 | name(model) {
8 | if (isBlank(model.name)) {
9 | model.errors.add('name', 'Please enter a name');
10 | model.hasValidated.pushObject('name');
11 | this.invalidate();
12 | }
13 | }
14 | });
15 |
--------------------------------------------------------------------------------
/app/validators/label.js:
--------------------------------------------------------------------------------
1 | import BaseValidator from './base';
2 | import {isBlank} from '@ember/utils';
3 |
4 | export default BaseValidator.create({
5 | properties: ['name'],
6 |
7 | name(model) {
8 | if (isBlank(model.name)) {
9 | model.errors.add('name', 'Please enter a name');
10 | model.hasValidated.pushObject('name');
11 | this.invalidate();
12 | }
13 | }
14 | });
--------------------------------------------------------------------------------
/app/validators/signup.js:
--------------------------------------------------------------------------------
1 | import NewUserValidator from 'ghost-admin/validators/new-user';
2 |
3 | export default NewUserValidator.create();
4 |
--------------------------------------------------------------------------------
/config/coverage.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node */
2 | module.exports = {
3 | parallel: true,
4 | reporters: ['cobertura']
5 | };
6 |
--------------------------------------------------------------------------------
/config/optional-features.json:
--------------------------------------------------------------------------------
1 | {
2 | "application-template-wrapper": false,
3 | "jquery-integration": true,
4 | "template-only-glimmer-components": true
5 | }
6 |
--------------------------------------------------------------------------------
/config/targets.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node */
2 |
3 | const browsers = [
4 | 'last 2 Chrome versions',
5 | 'last 2 Firefox versions',
6 | 'last 3 Safari versions',
7 | 'last 2 Edge versions'
8 | ];
9 |
10 | module.exports = {
11 | browsers
12 | };
13 |
--------------------------------------------------------------------------------
/lib/asset-delivery/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "asset-delivery",
3 | "keywords": [
4 | "ember-addon"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/lib/koenig-editor/addon/components/kg-action-bar.hbs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/lib/koenig-editor/addon/components/koenig-alt-input.hbs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/lib/koenig-editor/addon/components/koenig-caption-input.hbs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/lib/koenig-editor/addon/components/koenig-card-embed/nft.js:
--------------------------------------------------------------------------------
1 | import Component from '@ember/component';
2 | import classic from 'ember-classic-decorator';
3 |
4 | @classic
5 | export default class Nft extends Component {
6 | payload = null;
7 | }
8 |
--------------------------------------------------------------------------------
/lib/koenig-editor/addon/components/koenig-card-hr.hbs:
--------------------------------------------------------------------------------
1 |
11 |
12 |
--------------------------------------------------------------------------------
/lib/koenig-editor/addon/components/koenig-card-hr.js:
--------------------------------------------------------------------------------
1 | import Component from '@glimmer/component';
2 |
3 | export default class KoenigCardHrComponent extends Component {
4 | constructor() {
5 | super(...arguments);
6 | this.args.registerComponent(this);
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/lib/koenig-editor/addon/components/koenig-card-image/selector-tenor/gif.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |
5 |
--------------------------------------------------------------------------------
/lib/koenig-editor/addon/components/koenig-card-paywall.hbs:
--------------------------------------------------------------------------------
1 |
11 | Free public preview ↑ / ↓ Only visible to members
12 |
--------------------------------------------------------------------------------
/lib/koenig-editor/addon/components/koenig-card-paywall.js:
--------------------------------------------------------------------------------
1 | import Component from '@glimmer/component';
2 |
3 | export default class KoenigCardPaywallComponent extends Component {
4 | constructor() {
5 | super(...arguments);
6 | this.args.registerComponent(this);
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/lib/koenig-editor/addon/components/koenig-media-selector.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{yield (hash
3 | insertCard=this.insertCard
4 | close=this.args.close
5 | )}}
6 |
--------------------------------------------------------------------------------
/lib/koenig-editor/addon/components/koenig-menu-content.js:
--------------------------------------------------------------------------------
1 | import Component from '@glimmer/component';
2 | import {action} from '@ember/object';
3 |
4 | export default class KoenigMenuContentComponent extends Component {
5 | @action
6 | scrollIntoView(element, [doScroll]) {
7 | if (doScroll) {
8 | element.scrollIntoView({
9 | behavior: 'smooth',
10 | block: 'nearest'
11 | });
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/lib/koenig-editor/addon/components/koenig-settings-panel.hbs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/lib/koenig-editor/addon/helpers/clean-basic-html.js:
--------------------------------------------------------------------------------
1 | import cleanBasicHtml from '@tryghost/kg-clean-basic-html';
2 | import {helper} from '@ember/component/helper';
3 | import {isArray} from '@ember/array';
4 |
5 | export function cleanBasicHtmlHelper(html = '') {
6 | if (isArray(html)) {
7 | html = html[0] || '';
8 | }
9 |
10 | return cleanBasicHtml(html);
11 | }
12 |
13 | export default helper(cleanBasicHtmlHelper);
14 |
--------------------------------------------------------------------------------
/lib/koenig-editor/addon/options/basic-html-parser-plugins.js:
--------------------------------------------------------------------------------
1 | export function removeBR(node, builder, {addMarkerable, nodeFinished}) {
2 | if (node.nodeType !== 1 || node.tagName !== 'BR') {
3 | return;
4 | }
5 |
6 | addMarkerable(builder.createMarker(' '));
7 | nodeFinished();
8 | }
9 |
10 | export default [
11 | removeBR
12 | ];
13 |
--------------------------------------------------------------------------------
/lib/koenig-editor/addon/utils/extract-audio-metadata.js:
--------------------------------------------------------------------------------
1 | export default function extractAudioMetadata(file) {
2 | return new Promise((resolve) => {
3 | let audio = new Audio();
4 | let duration;
5 | const mimeType = file.type;
6 | audio.onloadedmetadata = function () {
7 | duration = audio.duration;
8 | resolve({
9 | duration,
10 | mimeType
11 | });
12 | };
13 | audio.src = URL.createObjectURL(file);
14 | });
15 | }
16 |
--------------------------------------------------------------------------------
/lib/koenig-editor/addon/utils/markup-utils.js:
--------------------------------------------------------------------------------
1 | export function getLinkMarkupFromRange(range) {
2 | let {headMarker, tailMarker} = range;
3 | if (headMarker && (headMarker === tailMarker || headMarker.next === tailMarker)) {
4 | return tailMarker.markups.findBy('tagName', 'a');
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/lib/koenig-editor/addon/utils/prettify-file-name.js:
--------------------------------------------------------------------------------
1 | export default function prettifyFileName(filename) {
2 | if (!filename || typeof filename !== 'string') {
3 | return '';
4 | }
5 | let updatedName = filename.split('.').slice(0, -1).join('.').replace(/[-_]/g,' ').replace(/[^\w\s]+/g,'').replace(/\s\s+/g, ' ');
6 | return updatedName.charAt(0).toUpperCase() + updatedName.slice(1);
7 | }
8 |
--------------------------------------------------------------------------------
/lib/koenig-editor/addon/utils/snippet-icon.js:
--------------------------------------------------------------------------------
1 | export default function snippetIcon(snippet) {
2 | let {mobiledoc} = snippet;
3 |
4 | if (mobiledoc.cards.length === 0) {
5 | return 'koenig/kg-card-type-snippet-text';
6 | }
7 |
8 | let hasRichText = mobiledoc.sections.some((section) => {
9 | return section[0] !== 10;
10 | });
11 |
12 | if (hasRichText) {
13 | return 'koenig/kg-card-type-snippet-combination';
14 | }
15 |
16 | return 'koenig/kg-card-type-snippet-block';
17 | }
18 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/kg-action-bar.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/kg-action-bar';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-alt-input.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-alt-input';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-basic-html-input.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-basic-html-input';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-basic-html-textarea.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-basic-html-textarea';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-caption-input.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-caption-input';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-card-audio.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-card-audio';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-card-before-after.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-card-before-after';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-card-bookmark.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-card-bookmark';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-card-button.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-card-button';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-card-callout.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-card-callout';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-card-code.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-card-code';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-card-email-cta.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-card-email-cta';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-card-email.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-card-email';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-card-embed.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-card-embed';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-card-embed/nft.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-card-embed/nft';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-card-file.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-card-file';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-card-gallery.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-card-gallery';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-card-header.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-card-header';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-card-hr.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-card-hr';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-card-html.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-card-html';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-card-image.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-card-image';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-card-image/selector-tenor.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-card-image/selector-tenor';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-card-image/selector-tenor/gif.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-card-image/selector-tenor/gif';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-card-markdown.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-card-markdown';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-card-paywall.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-card-paywall';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-card-product.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-card-product';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-card-toggle.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-card-toggle';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-card-video.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-card-video';
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-card.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-card';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-editor.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-editor';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-link-input.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-link-input';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-link-toolbar.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-link-toolbar';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-media-selector.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-media-selector';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-menu-content.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-menu-content';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-plus-menu.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-plus-menu';
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-settings-panel.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-settings-panel';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-slash-menu.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-slash-menu';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-snippet-input.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-snippet-input';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-text-replacement-html-input.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-text-replacement-html-input';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/components/koenig-toolbar.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/components/koenig-toolbar';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/helpers/card-is-available.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/helpers/card-is-available';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/helpers/clean-basic-html.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/helpers/clean-basic-html';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/helpers/kg-style.js:
--------------------------------------------------------------------------------
1 | export {default, kgStyle} from 'koenig-editor/helpers/kg-style';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/helpers/sanitize-html.js:
--------------------------------------------------------------------------------
1 | export {default, sanitizeHtml} from 'koenig-editor/helpers/sanitize-html';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/services/koenig-drag-drop-handler.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/services/koenig-drag-drop-handler';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/app/services/koenig-ui.js:
--------------------------------------------------------------------------------
1 | export {default} from 'koenig-editor/services/koenig-ui';
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/docs/specs/popup-toolbar.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/lib/koenig-editor/docs/specs/popup-toolbar.md
--------------------------------------------------------------------------------
/lib/koenig-editor/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node */
2 | 'use strict';
3 |
4 | module.exports = {
5 | name: 'koenig-editor',
6 |
7 | isDevelopingAddon() {
8 | return true;
9 | }
10 | };
11 |
--------------------------------------------------------------------------------
/lib/koenig-editor/public/icons/koenig/card-indicator-email.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/lib/koenig-editor/public/icons/koenig/card-indicator-html.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/lib/koenig-editor/public/icons/koenig/card-indicator-markdown.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/lib/koenig-editor/public/icons/koenig/code-block.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/lib/koenig-editor/public/icons/koenig/kg-add.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/lib/koenig-editor/public/icons/koenig/kg-bold.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/public/icons/koenig/kg-card-type-divider.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/lib/koenig-editor/public/icons/koenig/kg-card-type-other.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/lib/koenig-editor/public/icons/koenig/kg-card-type-snippet-block.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/lib/koenig-editor/public/icons/koenig/kg-card-type-toggle.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/lib/koenig-editor/public/icons/koenig/kg-card-type-unsplash.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/public/icons/koenig/kg-cta-border.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/lib/koenig-editor/public/icons/koenig/kg-header-full-center.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/lib/koenig-editor/public/icons/koenig/kg-header-wide-center.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/lib/koenig-editor/public/icons/koenig/kg-header-wide-right.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/lib/koenig-editor/public/icons/koenig/kg-heading-1.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/public/icons/koenig/kg-heading-2.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/public/icons/koenig/kg-img-regular.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/public/icons/koenig/kg-img-wide.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/public/icons/koenig/kg-italic.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/lib/koenig-editor/public/icons/koenig/kg-star.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/lib/koenig-editor/public/icons/koenig/kg-thin-delete.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/lib/koenig-editor/public/icons/koenig/kg-toggle-card-open-arrow.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/mirage/.eslintrc.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node */
2 | module.exports = {
3 | rules: {
4 | 'brace-style': 'off'
5 | }
6 | };
7 |
--------------------------------------------------------------------------------
/mirage/config/api-keys.js:
--------------------------------------------------------------------------------
1 | import {paginatedResponse} from '../utils';
2 |
3 | export default function mockApiKeys(server) {
4 | server.get('/api-keys/', paginatedResponse('api-keys'));
5 | server.post('/api-keys/');
6 | server.put('/api-keys/:id/');
7 | server.del('/api-keys/:id/');
8 | }
9 |
--------------------------------------------------------------------------------
/mirage/config/config.js:
--------------------------------------------------------------------------------
1 | import {isEmpty} from '@ember/utils';
2 |
3 | export default function mockConfig(server) {
4 | server.get('/config/', function ({db}) {
5 | if (isEmpty(db.configs)) {
6 | server.loadFixtures('configs');
7 | }
8 |
9 | return {
10 | config: db.configs.find(1)
11 | };
12 | });
13 | }
14 |
--------------------------------------------------------------------------------
/mirage/config/custom-theme-settings.js:
--------------------------------------------------------------------------------
1 | export default function mockCustomThemeSettings(server) {
2 | server.get('/custom_theme_settings');
3 | }
4 |
--------------------------------------------------------------------------------
/mirage/config/emails.js:
--------------------------------------------------------------------------------
1 | export default function mockEmails(/* server */) {
2 | // emails are currently only returned as an embedded record in post models
3 | }
4 |
--------------------------------------------------------------------------------
/mirage/config/roles.js:
--------------------------------------------------------------------------------
1 | export default function mockRoles(server) {
2 | server.get('/roles/', function ({roles}, {queryParams}) {
3 | if (queryParams.permissions === 'assign') {
4 | return roles.find([1, 2, 3, 5]);
5 | }
6 |
7 | return roles.all();
8 | });
9 | }
10 |
--------------------------------------------------------------------------------
/mirage/config/site.js:
--------------------------------------------------------------------------------
1 | import {isEmpty} from '@ember/utils';
2 |
3 | export default function mockSite(server) {
4 | server.get('/site/', function ({db}) {
5 | if (isEmpty(db.sites)) {
6 | server.loadFixtures('sites');
7 | }
8 |
9 | return {
10 | site: db.sites.find(1)
11 | };
12 | });
13 | }
14 |
--------------------------------------------------------------------------------
/mirage/config/snippets.js:
--------------------------------------------------------------------------------
1 | export default function mockSnippets(server) {
2 | server.get('/snippets/');
3 | server.post('/snippets/');
4 | server.put('/snippets/:id/');
5 | server.del('/snippets/:id/');
6 | }
7 |
--------------------------------------------------------------------------------
/mirage/factories/invite.js:
--------------------------------------------------------------------------------
1 | import moment from 'moment';
2 | import {Factory} from 'miragejs';
3 |
4 | export default Factory.extend({
5 | token(i) { return `${i}-token`; },
6 | email(i) { return `invited-user-${i}@example.com`; },
7 | expires() { return moment.utc().add(1, 'day').valueOf(); },
8 | createdAt() { return moment.utc().format(); },
9 | createdBy() { return 1; },
10 | updatedAt() { return moment.utc().format(); },
11 | updatedBy() { return 1; },
12 | status() { return 'sent'; }
13 | });
14 |
--------------------------------------------------------------------------------
/mirage/factories/label.js:
--------------------------------------------------------------------------------
1 | import moment from 'moment';
2 | import {Factory} from 'miragejs';
3 |
4 | export default Factory.extend({
5 | createdAt() { return moment().toISOString(); },
6 | createdBy: 1,
7 | name(i) { return `Label ${i}`; },
8 | slug(i) { return `label-${i}`; },
9 | updatedAt() { return moment().toISOString(); },
10 | updatedBy: 1,
11 | count() {
12 | // this gets updated automatically by the label serializer
13 | return {members: 0};
14 | }
15 | });
16 |
--------------------------------------------------------------------------------
/mirage/factories/notification.js:
--------------------------------------------------------------------------------
1 | import {Factory} from 'miragejs';
2 |
3 | export default Factory.extend({
4 | dismissible: true,
5 | message: 'This is an alert',
6 | status: 'alert',
7 | type: 'error'
8 | });
9 |
--------------------------------------------------------------------------------
/mirage/factories/role.js:
--------------------------------------------------------------------------------
1 | import {Factory} from 'miragejs';
2 |
3 | export default Factory.extend({
4 | createdAt: '2013-11-25T14:48:11.000Z',
5 | createdBy: 1,
6 | description(i) { return `Role ${i}`; },
7 | name: '',
8 | updatedAt: '2013-11-25T14:48:11.000Z',
9 | updatedBy: 1
10 | });
11 |
--------------------------------------------------------------------------------
/mirage/factories/subscription.js:
--------------------------------------------------------------------------------
1 | import {Factory} from 'miragejs';
2 |
3 | export default Factory.extend({
4 | });
5 |
--------------------------------------------------------------------------------
/mirage/factories/tier.js:
--------------------------------------------------------------------------------
1 | import {Factory} from 'miragejs';
2 |
3 | export default Factory.extend({
4 | name(i) { return `Tier ${i}`; },
5 | description(i) { return `Description for tier ${i}`; },
6 | active: true,
7 | slug(i) { return `tier-${i}`;},
8 | type: 'paid',
9 | visibility: 'none',
10 | currency: 'usd',
11 | monthly_price: 500,
12 | yearly_price: 5000
13 | });
14 |
--------------------------------------------------------------------------------
/mirage/fixtures/configs.js:
--------------------------------------------------------------------------------
1 | export default [{
2 | clientExtensions: {},
3 | database: 'mysql',
4 | enableDeveloperExperiments: false,
5 | environment: 'development',
6 | labs: {},
7 | mail: 'SMTP',
8 | version: '2.15.0',
9 | useGravatar: 'true'
10 | }];
11 |
--------------------------------------------------------------------------------
/mirage/fixtures/newsletters.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable camelcase */
2 | export default [
3 | {
4 | id: 1,
5 | name: 'Default newsletter',
6 | slug: 'default-newsletter',
7 | status: 'active',
8 | subscribeOnSignup: true
9 | }
10 | ];
11 |
--------------------------------------------------------------------------------
/mirage/fixtures/sites.js:
--------------------------------------------------------------------------------
1 | export default [{
2 | title: 'Test Blog',
3 | url: `${window.location.origin}/`
4 | }];
5 |
--------------------------------------------------------------------------------
/mirage/fixtures/themes.js:
--------------------------------------------------------------------------------
1 | export default [
2 | {
3 | name: 'casper',
4 | package: {
5 | name: 'casper',
6 | version: '1.0'
7 | },
8 | active: true
9 | },
10 | {
11 | name: 'foo',
12 | package: {
13 | name: 'Foo',
14 | version: '0.1'
15 | }
16 | },
17 | {
18 | name: 'bar'
19 | }
20 | ];
21 |
--------------------------------------------------------------------------------
/mirage/models/api-key.js:
--------------------------------------------------------------------------------
1 | import {Model, belongsTo} from 'miragejs';
2 |
3 | export default Model.extend({
4 | integration: belongsTo()
5 | });
6 |
--------------------------------------------------------------------------------
/mirage/models/config.js:
--------------------------------------------------------------------------------
1 | import {Model} from 'miragejs';
2 |
3 | export default Model.extend({
4 | });
5 |
--------------------------------------------------------------------------------
/mirage/models/custom-theme-setting.js:
--------------------------------------------------------------------------------
1 | import {Model} from 'miragejs';
2 |
3 | export default Model.extend({});
4 |
--------------------------------------------------------------------------------
/mirage/models/email.js:
--------------------------------------------------------------------------------
1 | import {Model, belongsTo} from 'miragejs';
2 |
3 | export default Model.extend({
4 | post: belongsTo()
5 | });
6 |
--------------------------------------------------------------------------------
/mirage/models/integration.js:
--------------------------------------------------------------------------------
1 | import {Model, hasMany} from 'miragejs';
2 |
3 | export default Model.extend({
4 | apiKeys: hasMany(),
5 | webhooks: hasMany()
6 | });
7 |
--------------------------------------------------------------------------------
/mirage/models/invite.js:
--------------------------------------------------------------------------------
1 | import {Model, belongsTo} from 'miragejs';
2 |
3 | export default Model.extend({
4 | role: belongsTo()
5 | });
6 |
--------------------------------------------------------------------------------
/mirage/models/label.js:
--------------------------------------------------------------------------------
1 | import {Model, hasMany} from 'miragejs';
2 |
3 | export default Model.extend({
4 | members: hasMany()
5 | });
6 |
--------------------------------------------------------------------------------
/mirage/models/member-activity-event.js:
--------------------------------------------------------------------------------
1 | import {Model, belongsTo} from 'miragejs';
2 |
3 | export default Model.extend({
4 | email: belongsTo(),
5 | member: belongsTo()
6 | });
7 |
--------------------------------------------------------------------------------
/mirage/models/member.js:
--------------------------------------------------------------------------------
1 | import {Model, hasMany} from 'miragejs';
2 |
3 | export default Model.extend({
4 | labels: hasMany(),
5 | tiers: hasMany(),
6 | newsletters: hasMany(),
7 | subscriptions: hasMany()
8 | });
9 |
--------------------------------------------------------------------------------
/mirage/models/newsletter.js:
--------------------------------------------------------------------------------
1 | import {Model, hasMany} from 'miragejs';
2 |
3 | export default Model.extend({
4 | members: hasMany()
5 | });
6 |
--------------------------------------------------------------------------------
/mirage/models/notification.js:
--------------------------------------------------------------------------------
1 | import {Model} from 'miragejs';
2 |
3 | export default Model.extend({
4 | });
5 |
--------------------------------------------------------------------------------
/mirage/models/page.js:
--------------------------------------------------------------------------------
1 | import PostModel from './post';
2 |
3 | export default PostModel.extend({
4 |
5 | });
6 |
--------------------------------------------------------------------------------
/mirage/models/post.js:
--------------------------------------------------------------------------------
1 | import {Model, belongsTo, hasMany} from 'miragejs';
2 |
3 | export default Model.extend({
4 | tags: hasMany(),
5 | authors: hasMany('user'),
6 | email: belongsTo(),
7 | newsletter: belongsTo()
8 | });
9 |
--------------------------------------------------------------------------------
/mirage/models/role.js:
--------------------------------------------------------------------------------
1 | import {Model} from 'miragejs';
2 |
3 | export default Model.extend({
4 | });
5 |
--------------------------------------------------------------------------------
/mirage/models/site.js:
--------------------------------------------------------------------------------
1 | import {Model} from 'miragejs';
2 |
3 | export default Model.extend({
4 | });
5 |
--------------------------------------------------------------------------------
/mirage/models/snippet.js:
--------------------------------------------------------------------------------
1 | import {Model} from 'miragejs';
2 |
3 | export default Model.extend({});
4 |
--------------------------------------------------------------------------------
/mirage/models/subscriber.js:
--------------------------------------------------------------------------------
1 | import {Model} from 'miragejs';
2 |
3 | export default Model.extend({
4 | });
5 |
--------------------------------------------------------------------------------
/mirage/models/subscription.js:
--------------------------------------------------------------------------------
1 | import {Model, belongsTo} from 'miragejs';
2 |
3 | export default Model.extend({
4 | member: belongsTo(),
5 | tier: belongsTo()
6 | });
7 |
--------------------------------------------------------------------------------
/mirage/models/tag.js:
--------------------------------------------------------------------------------
1 | import {Model, hasMany} from 'miragejs';
2 |
3 | export default Model.extend({
4 | posts: hasMany()
5 | });
6 |
--------------------------------------------------------------------------------
/mirage/models/theme.js:
--------------------------------------------------------------------------------
1 | import {Model} from 'miragejs';
2 |
3 | export default Model.extend({
4 | });
5 |
--------------------------------------------------------------------------------
/mirage/models/tier.js:
--------------------------------------------------------------------------------
1 | import {Model, hasMany} from 'miragejs';
2 |
3 | export default Model.extend({
4 | members: hasMany()
5 | });
6 |
--------------------------------------------------------------------------------
/mirage/models/user.js:
--------------------------------------------------------------------------------
1 | import {Model, hasMany} from 'miragejs';
2 |
3 | export default Model.extend({
4 | // used by the serializer to determine whether
5 | // or not to include the post count
6 | postCount: false,
7 |
8 | roles: hasMany(),
9 | posts: hasMany()
10 | });
11 |
--------------------------------------------------------------------------------
/mirage/models/webhook.js:
--------------------------------------------------------------------------------
1 | import {Model, belongsTo} from 'miragejs';
2 |
3 | export default Model.extend({
4 | integration: belongsTo()
5 | });
6 |
--------------------------------------------------------------------------------
/mirage/serializers/integration.js:
--------------------------------------------------------------------------------
1 | import BaseSerializer from './application';
2 | import {camelize} from '@ember/string';
3 |
4 | export default BaseSerializer.extend({
5 | embed: true,
6 |
7 | include(request) {
8 | if (!request.queryParams.include) {
9 | return;
10 | }
11 | return request.queryParams.include.split(',').map(camelize);
12 | }
13 | });
14 |
--------------------------------------------------------------------------------
/mirage/serializers/page.js:
--------------------------------------------------------------------------------
1 | import PostSerializer from './post';
2 |
3 | export default PostSerializer.extend({});
4 |
--------------------------------------------------------------------------------
/mirage/serializers/post.js:
--------------------------------------------------------------------------------
1 | import BaseSerializer from './application';
2 |
3 | export default BaseSerializer.extend({
4 | embed: true,
5 |
6 | include(/*request*/) {
7 | let includes = [];
8 |
9 | includes.push('tags');
10 | includes.push('authors');
11 |
12 | return includes;
13 | }
14 | });
15 |
--------------------------------------------------------------------------------
/public/assets/fonts/Inter.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/fonts/Inter.ttf
--------------------------------------------------------------------------------
/public/assets/icons/add-stroke.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/add.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/public/assets/icons/align-center.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/public/assets/icons/align-left.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/public/assets/icons/arrow-down-stroke.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/arrow-down.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/public/assets/icons/arrow-left-stroke.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/arrow-left-tail.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/arrow-left.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/public/assets/icons/arrow-right-stroke.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/arrow-right-tail.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/arrow-right.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/public/assets/icons/arrow-up-stroke.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/arrow2-down.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/bookmark-article.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/brackets.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/calendar.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/check-2.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/check-circle-stroke.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/check.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/circle-ellipsis.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/clock.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/close-stroke.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/close.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/compass-2.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/cross-circle.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/dividers.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/dotdotdot.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/download.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/public/assets/icons/email-at.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/email-body.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/email-footer.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/email-header.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/email-member.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/email-name.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/email-stroke.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/public/assets/icons/email-unread.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/external.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/facebook.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
--------------------------------------------------------------------------------
/public/assets/icons/feature-image.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/public/assets/icons/file-upload.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/filter.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/public/assets/icons/firstpromoter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/icons/firstpromoter.png
--------------------------------------------------------------------------------
/public/assets/icons/get-started.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/public/assets/icons/ghost-logo-orb.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/ghost-orb.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/google-search.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/grab.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/public/assets/icons/graph-line.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/heart.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/house.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/info.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/list-bullet.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/list-number.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/lock.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/member-add.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/members.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/mobile-phone.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/moon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/mute.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/navigation.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/no-data-line-chart.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/page.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/pause.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/pencil-circle.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/percentage.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/pin.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/play.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/plus.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/public/assets/icons/portal-icon-1.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/portal-icon-2.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/post.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/posts.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/reload.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/retry.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/public/assets/icons/send-email.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/sidemenu-open.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/sidemenu.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/public/assets/icons/staff.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/star-filled.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/sync.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/tag.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/text.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/unmute.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/unsplash-heart.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/public/assets/icons/unsplash.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/public/assets/icons/unsubscribed.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/upload.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/v-ellipsis.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/view-site.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/icons/warning-stroke.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/img/404-ghost.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/404-ghost.png
--------------------------------------------------------------------------------
/public/assets/img/404-ghost@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/404-ghost@2x.png
--------------------------------------------------------------------------------
/public/assets/img/abstract-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/abstract-2.jpg
--------------------------------------------------------------------------------
/public/assets/img/abstract.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/abstract.jpg
--------------------------------------------------------------------------------
/public/assets/img/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/apple-touch-icon.png
--------------------------------------------------------------------------------
/public/assets/img/buffer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/buffer.png
--------------------------------------------------------------------------------
/public/assets/img/community-background.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/community-background.jpg
--------------------------------------------------------------------------------
/public/assets/img/community.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/community.jpg
--------------------------------------------------------------------------------
/public/assets/img/dashboard-feature-image.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/dashboard-feature-image.jpeg
--------------------------------------------------------------------------------
/public/assets/img/dashboard/bp1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/dashboard/bp1.jpg
--------------------------------------------------------------------------------
/public/assets/img/dashboard/bp2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/dashboard/bp2.jpg
--------------------------------------------------------------------------------
/public/assets/img/dashboard/join-community.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/dashboard/join-community.jpg
--------------------------------------------------------------------------------
/public/assets/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/favicon.ico
--------------------------------------------------------------------------------
/public/assets/img/firstpromoter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/firstpromoter.png
--------------------------------------------------------------------------------
/public/assets/img/footer-marketplace-bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/footer-marketplace-bg.png
--------------------------------------------------------------------------------
/public/assets/img/get-started.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/get-started.jpg
--------------------------------------------------------------------------------
/public/assets/img/google-analytics.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/google-analytics.png
--------------------------------------------------------------------------------
/public/assets/img/install-welcome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/install-welcome.png
--------------------------------------------------------------------------------
/public/assets/img/invite-placeholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/invite-placeholder.png
--------------------------------------------------------------------------------
/public/assets/img/large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/large.png
--------------------------------------------------------------------------------
/public/assets/img/launch-wizard-bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/launch-wizard-bg.png
--------------------------------------------------------------------------------
/public/assets/img/loadingcat.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/loadingcat.gif
--------------------------------------------------------------------------------
/public/assets/img/logos/ghost-logo-black-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/logos/ghost-logo-black-1.png
--------------------------------------------------------------------------------
/public/assets/img/logos/orb-black-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/logos/orb-black-1.png
--------------------------------------------------------------------------------
/public/assets/img/logos/orb-black-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/logos/orb-black-2.png
--------------------------------------------------------------------------------
/public/assets/img/logos/orb-black-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/logos/orb-black-3.png
--------------------------------------------------------------------------------
/public/assets/img/logos/orb-black-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/logos/orb-black-4.png
--------------------------------------------------------------------------------
/public/assets/img/logos/orb-black-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/logos/orb-black-5.png
--------------------------------------------------------------------------------
/public/assets/img/marketing/members-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/marketing/members-1.jpg
--------------------------------------------------------------------------------
/public/assets/img/marketing/members-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/marketing/members-2.jpg
--------------------------------------------------------------------------------
/public/assets/img/marketing/offers-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/marketing/offers-1.jpg
--------------------------------------------------------------------------------
/public/assets/img/marketing/offers-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/marketing/offers-2.jpg
--------------------------------------------------------------------------------
/public/assets/img/marketing/offers-3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/marketing/offers-3.jpg
--------------------------------------------------------------------------------
/public/assets/img/medium.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/medium.png
--------------------------------------------------------------------------------
/public/assets/img/more.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/more.png
--------------------------------------------------------------------------------
/public/assets/img/newsletter-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/newsletter-1.jpg
--------------------------------------------------------------------------------
/public/assets/img/newsletter-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/newsletter-2.jpg
--------------------------------------------------------------------------------
/public/assets/img/orb-squircle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/orb-squircle.png
--------------------------------------------------------------------------------
/public/assets/img/patreon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/assets/img/plausible.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/plausible.png
--------------------------------------------------------------------------------
/public/assets/img/resource-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/resource-1.jpg
--------------------------------------------------------------------------------
/public/assets/img/slackicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/slackicon.png
--------------------------------------------------------------------------------
/public/assets/img/small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/small.png
--------------------------------------------------------------------------------
/public/assets/img/themes/Alto-cut.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/themes/Alto-cut.jpg
--------------------------------------------------------------------------------
/public/assets/img/themes/Alto.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/themes/Alto.jpg
--------------------------------------------------------------------------------
/public/assets/img/themes/Alto.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/themes/Alto.png
--------------------------------------------------------------------------------
/public/assets/img/themes/Bulletin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/themes/Bulletin.png
--------------------------------------------------------------------------------
/public/assets/img/themes/Casper.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/themes/Casper.jpg
--------------------------------------------------------------------------------
/public/assets/img/themes/Dawn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/themes/Dawn.png
--------------------------------------------------------------------------------
/public/assets/img/themes/Digest.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/themes/Digest.png
--------------------------------------------------------------------------------
/public/assets/img/themes/Dope.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/themes/Dope.png
--------------------------------------------------------------------------------
/public/assets/img/themes/Ease-cut.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/themes/Ease-cut.jpg
--------------------------------------------------------------------------------
/public/assets/img/themes/Ease.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/themes/Ease.jpg
--------------------------------------------------------------------------------
/public/assets/img/themes/Ease.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/themes/Ease.png
--------------------------------------------------------------------------------
/public/assets/img/themes/Edge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/themes/Edge.png
--------------------------------------------------------------------------------
/public/assets/img/themes/Edition-cut.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/themes/Edition-cut.jpg
--------------------------------------------------------------------------------
/public/assets/img/themes/Edition.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/themes/Edition.jpg
--------------------------------------------------------------------------------
/public/assets/img/themes/Edition.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/themes/Edition.png
--------------------------------------------------------------------------------
/public/assets/img/themes/Headline.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/themes/Headline.jpg
--------------------------------------------------------------------------------
/public/assets/img/themes/Journal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/themes/Journal.png
--------------------------------------------------------------------------------
/public/assets/img/themes/London-cut.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/themes/London-cut.jpg
--------------------------------------------------------------------------------
/public/assets/img/themes/London.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/themes/London.jpg
--------------------------------------------------------------------------------
/public/assets/img/themes/Ruby.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/themes/Ruby.png
--------------------------------------------------------------------------------
/public/assets/img/themes/Wave.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/themes/Wave.png
--------------------------------------------------------------------------------
/public/assets/img/touch-icon-ipad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/touch-icon-ipad.png
--------------------------------------------------------------------------------
/public/assets/img/touch-icon-iphone.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/touch-icon-iphone.png
--------------------------------------------------------------------------------
/public/assets/img/ulysses.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/ulysses.png
--------------------------------------------------------------------------------
/public/assets/img/unsplash-404.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/unsplash-404.png
--------------------------------------------------------------------------------
/public/assets/img/user-cover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/user-cover.png
--------------------------------------------------------------------------------
/public/assets/img/user-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/user-image.png
--------------------------------------------------------------------------------
/public/assets/img/users.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/users.png
--------------------------------------------------------------------------------
/public/assets/img/zero-bounce.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/public/assets/img/zero-bounce.png
--------------------------------------------------------------------------------
/tests/.eslintrc.js:
--------------------------------------------------------------------------------
1 | /* eslint-env node */
2 | module.exports = {
3 | env: {
4 | embertest: true,
5 | mocha: true
6 | },
7 | rules: {
8 | 'ghost/ember/no-invalid-debug-function-arguments': 'off'
9 | }
10 | };
11 |
--------------------------------------------------------------------------------
/tests/helpers/login-as-role.js:
--------------------------------------------------------------------------------
1 | import {authenticateSession, invalidateSession} from 'ember-simple-auth/test-support';
2 |
3 | export default async function loginRole(roleName, server) {
4 | const role = server.create('role', {name: roleName});
5 | const user = server.create('user', {roles: [role], slug: 'test-user'});
6 | await invalidateSession();
7 | await authenticateSession();
8 |
9 | return user;
10 | }
11 |
--------------------------------------------------------------------------------
/tests/helpers/newsletters.js:
--------------------------------------------------------------------------------
1 | export function enableNewsletters(server, enabled = true) {
2 | server.db.settings.find({key: 'editor_default_email_recipients'})
3 | ? server.db.settings.update({key: 'editor_default_email_recipients'}, {value: (enabled ? 'visibility' : 'disabled')})
4 | : server.create('setting', {key: 'editor_default_email_recipients', value: (enabled ? 'visibility' : 'disabled'), group: 'editor'});
5 | }
6 |
7 | export function disableNewsletters(server) {
8 | enableNewsletters(server, false);
9 | }
10 |
--------------------------------------------------------------------------------
/tests/helpers/visit.js:
--------------------------------------------------------------------------------
1 | // TODO: remove once bug is fixed in Ember
2 | // see https://github.com/emberjs/ember-test-helpers/issues/332
3 |
4 | import {visit as _visit, settled} from '@ember/test-helpers';
5 |
6 | export async function visit(url) {
7 | try {
8 | await _visit(url);
9 | } catch (e) {
10 | if (e.message !== 'TransitionAborted') {
11 | throw e;
12 | }
13 | }
14 |
15 | await settled();
16 | }
17 |
--------------------------------------------------------------------------------
/tests/unit/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TryGhost/Admin/5c568871669ed0bf71d52a6e8abf4a5f9fe0b7fd/tests/unit/.gitkeep
--------------------------------------------------------------------------------
/tests/unit/helpers/highlighted-text-test.js:
--------------------------------------------------------------------------------
1 | import {
2 | describe,
3 | it
4 | } from 'mocha';
5 | import {expect} from 'chai';
6 | import {
7 | highlightedText
8 | } from 'ghost-admin/helpers/highlighted-text';
9 |
10 | describe('Unit: Helper: highlighted-text', function () {
11 | it('works', function () {
12 | let result = highlightedText(['Test', 'e']);
13 | expect(result).to.be.an('object');
14 | expect(result.string).to.equal('Test');
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/tests/unit/models/setting-test.js:
--------------------------------------------------------------------------------
1 | import {describe, it} from 'mocha';
2 | import {expect} from 'chai';
3 | import {setupTest} from 'ember-mocha';
4 |
5 | describe('Unit: Model: setting', function () {
6 | setupTest();
7 |
8 | it('has a validation type of "setting"', function () {
9 | let model = this.owner.lookup('service:store').createRecord('setting');
10 |
11 | expect(model.get('validationType')).to.equal('setting');
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/tests/unit/models/tag-test.js:
--------------------------------------------------------------------------------
1 | import {describe, it} from 'mocha';
2 | import {expect} from 'chai';
3 | import {setupTest} from 'ember-mocha';
4 |
5 | describe('Unit: Model: tag', function () {
6 | setupTest();
7 |
8 | it('has a validation type of "tag"', function () {
9 | let model = this.owner.lookup('service:store').createRecord('tag');
10 |
11 | expect(model.get('validationType')).to.equal('tag');
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/tests/unit/routes/explore-test.js:
--------------------------------------------------------------------------------
1 | import {describe, it} from 'mocha';
2 | import {expect} from 'chai';
3 | import {setupTest} from 'ember-mocha';
4 |
5 | describe('Unit | Route | explore', function () {
6 | setupTest();
7 |
8 | it('exists', function () {
9 | let route = this.owner.lookup('route:explore');
10 | expect(route).to.be.ok;
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/tests/unit/services/limit-test.js:
--------------------------------------------------------------------------------
1 | import {describe, it} from 'mocha';
2 | import {expect} from 'chai';
3 | import {setupTest} from 'ember-mocha';
4 |
5 | describe('Unit | Service | limit', function () {
6 | setupTest();
7 |
8 | let limitService;
9 |
10 | beforeEach(function () {
11 | limitService = this.owner.lookup('service:limit');
12 | });
13 |
14 | it('exists', function () {
15 | expect(limitService).to.be.ok;
16 | });
17 | });
18 |
--------------------------------------------------------------------------------