ghost 5.61.3 → 5.63.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/components/tryghost-adapter-cache-memory-ttl-5.63.0.tgz +0 -0
  2. package/components/tryghost-adapter-cache-redis-5.63.0.tgz +0 -0
  3. package/components/{tryghost-adapter-manager-5.61.3.tgz → tryghost-adapter-manager-5.63.0.tgz} +0 -0
  4. package/components/tryghost-announcement-bar-settings-5.63.0.tgz +0 -0
  5. package/components/tryghost-api-framework-5.63.0.tgz +0 -0
  6. package/components/{tryghost-api-version-compatibility-service-5.61.3.tgz → tryghost-api-version-compatibility-service-5.63.0.tgz} +0 -0
  7. package/components/{tryghost-audience-feedback-5.61.3.tgz → tryghost-audience-feedback-5.63.0.tgz} +0 -0
  8. package/components/tryghost-bookshelf-repository-5.63.0.tgz +0 -0
  9. package/components/tryghost-bootstrap-socket-5.63.0.tgz +0 -0
  10. package/components/tryghost-collections-5.63.0.tgz +0 -0
  11. package/components/{tryghost-constants-5.61.3.tgz → tryghost-constants-5.63.0.tgz} +0 -0
  12. package/components/tryghost-custom-theme-settings-service-5.63.0.tgz +0 -0
  13. package/components/tryghost-data-generator-5.63.0.tgz +0 -0
  14. package/components/tryghost-domain-events-5.63.0.tgz +0 -0
  15. package/components/tryghost-donations-5.63.0.tgz +0 -0
  16. package/components/tryghost-dynamic-routing-events-5.63.0.tgz +0 -0
  17. package/components/tryghost-email-analytics-provider-mailgun-5.63.0.tgz +0 -0
  18. package/components/{tryghost-email-analytics-service-5.61.3.tgz → tryghost-email-analytics-service-5.63.0.tgz} +0 -0
  19. package/components/tryghost-email-content-generator-5.63.0.tgz +0 -0
  20. package/components/tryghost-email-events-5.63.0.tgz +0 -0
  21. package/components/{tryghost-email-service-5.61.3.tgz → tryghost-email-service-5.63.0.tgz} +0 -0
  22. package/components/tryghost-email-suppression-list-5.63.0.tgz +0 -0
  23. package/components/tryghost-event-aware-cache-wrapper-5.63.0.tgz +0 -0
  24. package/components/tryghost-express-dynamic-redirects-5.63.0.tgz +0 -0
  25. package/components/{tryghost-external-media-inliner-5.61.3.tgz → tryghost-external-media-inliner-5.63.0.tgz} +0 -0
  26. package/components/{tryghost-extract-api-key-5.61.3.tgz → tryghost-extract-api-key-5.63.0.tgz} +0 -0
  27. package/components/{tryghost-html-to-plaintext-5.61.3.tgz → tryghost-html-to-plaintext-5.63.0.tgz} +0 -0
  28. package/components/tryghost-i18n-5.63.0.tgz +0 -0
  29. package/components/{tryghost-importer-handler-content-files-5.61.3.tgz → tryghost-importer-handler-content-files-5.63.0.tgz} +0 -0
  30. package/components/{tryghost-importer-revue-5.61.3.tgz → tryghost-importer-revue-5.63.0.tgz} +0 -0
  31. package/components/tryghost-in-memory-repository-5.63.0.tgz +0 -0
  32. package/components/{tryghost-job-manager-5.61.3.tgz → tryghost-job-manager-5.63.0.tgz} +0 -0
  33. package/components/tryghost-link-redirects-5.63.0.tgz +0 -0
  34. package/components/tryghost-link-replacer-5.63.0.tgz +0 -0
  35. package/components/{tryghost-link-tracking-5.61.3.tgz → tryghost-link-tracking-5.63.0.tgz} +0 -0
  36. package/components/tryghost-magic-link-5.63.0.tgz +0 -0
  37. package/components/tryghost-mail-events-5.63.0.tgz +0 -0
  38. package/components/tryghost-mailgun-client-5.63.0.tgz +0 -0
  39. package/components/{tryghost-member-attribution-5.61.3.tgz → tryghost-member-attribution-5.63.0.tgz} +0 -0
  40. package/components/tryghost-member-events-5.63.0.tgz +0 -0
  41. package/components/tryghost-members-api-5.63.0.tgz +0 -0
  42. package/components/{tryghost-members-csv-5.61.3.tgz → tryghost-members-csv-5.63.0.tgz} +0 -0
  43. package/components/{tryghost-members-events-service-5.61.3.tgz → tryghost-members-events-service-5.63.0.tgz} +0 -0
  44. package/components/{tryghost-members-importer-5.61.3.tgz → tryghost-members-importer-5.63.0.tgz} +0 -0
  45. package/components/tryghost-members-offers-5.63.0.tgz +0 -0
  46. package/components/tryghost-members-payments-5.63.0.tgz +0 -0
  47. package/components/tryghost-members-ssr-5.63.0.tgz +0 -0
  48. package/components/{tryghost-members-stripe-service-5.61.3.tgz → tryghost-members-stripe-service-5.63.0.tgz} +0 -0
  49. package/components/tryghost-mentions-email-report-5.63.0.tgz +0 -0
  50. package/components/{tryghost-milestones-5.61.3.tgz → tryghost-milestones-5.63.0.tgz} +0 -0
  51. package/components/{tryghost-minifier-5.61.3.tgz → tryghost-minifier-5.63.0.tgz} +0 -0
  52. package/components/tryghost-model-to-domain-event-interceptor-5.63.0.tgz +0 -0
  53. package/components/{tryghost-mw-api-version-mismatch-5.61.3.tgz → tryghost-mw-api-version-mismatch-5.63.0.tgz} +0 -0
  54. package/components/tryghost-mw-cache-control-5.63.0.tgz +0 -0
  55. package/components/{tryghost-mw-error-handler-5.61.3.tgz → tryghost-mw-error-handler-5.63.0.tgz} +0 -0
  56. package/components/tryghost-mw-session-from-token-5.63.0.tgz +0 -0
  57. package/components/tryghost-mw-update-user-last-seen-5.63.0.tgz +0 -0
  58. package/components/tryghost-mw-version-match-5.63.0.tgz +0 -0
  59. package/components/tryghost-mw-vhost-5.63.0.tgz +0 -0
  60. package/components/tryghost-nql-filter-expansions-5.63.0.tgz +0 -0
  61. package/components/tryghost-oembed-service-5.63.0.tgz +0 -0
  62. package/components/{tryghost-package-json-5.61.3.tgz → tryghost-package-json-5.63.0.tgz} +0 -0
  63. package/components/tryghost-post-events-5.63.0.tgz +0 -0
  64. package/components/tryghost-post-revisions-5.63.0.tgz +0 -0
  65. package/components/tryghost-posts-service-5.63.0.tgz +0 -0
  66. package/components/tryghost-recommendations-5.63.0.tgz +0 -0
  67. package/components/tryghost-referrers-5.63.0.tgz +0 -0
  68. package/components/{tryghost-security-5.61.3.tgz → tryghost-security-5.63.0.tgz} +0 -0
  69. package/components/tryghost-session-service-5.63.0.tgz +0 -0
  70. package/components/tryghost-settings-path-manager-5.63.0.tgz +0 -0
  71. package/components/tryghost-slack-notifications-5.63.0.tgz +0 -0
  72. package/components/{tryghost-staff-service-5.61.3.tgz → tryghost-staff-service-5.63.0.tgz} +0 -0
  73. package/components/tryghost-stats-service-5.63.0.tgz +0 -0
  74. package/components/{tryghost-tiers-5.61.3.tgz → tryghost-tiers-5.63.0.tgz} +0 -0
  75. package/components/{tryghost-update-check-service-5.61.3.tgz → tryghost-update-check-service-5.63.0.tgz} +0 -0
  76. package/components/{tryghost-verification-trigger-5.61.3.tgz → tryghost-verification-trigger-5.63.0.tgz} +0 -0
  77. package/components/tryghost-version-notifications-data-service-5.63.0.tgz +0 -0
  78. package/components/tryghost-webmentions-5.63.0.tgz +0 -0
  79. package/core/built/admin/assets/{chunk.143.da84b3b434141aff0f01.js → chunk.143.1c5d21facf1f9b9beef9.js} +6 -5
  80. package/core/built/admin/assets/{chunk.178.659d369f286d4162b294.js → chunk.178.43b03c9ac011a54262b0.js} +4 -4
  81. package/core/built/admin/assets/{chunk.208.dbf172ad32f72f21a5dc.js → chunk.237.9b7032162949850f6c76.js} +778 -702
  82. package/core/built/admin/assets/{ghost-8a4e981c272f793157133814ca7c7e84.css → ghost-33664cad4cd6664a8b5fa56e62c5005f.css} +1 -1
  83. package/core/built/admin/assets/{ghost-54f84395df6a6fb47b37008ded8eba22.js → ghost-7c3f2de2ec83e591ad9f9db5165b2733.js} +68 -63
  84. package/core/built/admin/assets/ghost-dark-0452daeaee3a9b16dcd954ea60dad518.css +1 -0
  85. package/core/built/admin/assets/{vendor-3631184082d609038638c1e169a002e7.js → vendor-f8ce8bd43cf5dad6608f828ab48cee9b.js} +249 -322
  86. package/core/built/admin/index.html +6 -6
  87. package/core/frontend/helpers/foreach.js +8 -0
  88. package/core/frontend/helpers/get.js +3 -0
  89. package/core/frontend/meta/schema.js +1 -1
  90. package/core/frontend/services/data/checks.js +6 -0
  91. package/core/frontend/src/cards/css/collection.css +186 -0
  92. package/core/frontend/src/cards/css/header_v2.css +19 -23
  93. package/core/frontend/src/cards/css/signup.css +20 -23
  94. package/core/server/adapters/storage/LocalStorageBase.js +1 -8
  95. package/core/server/api/endpoints/recommendations-public.js +44 -5
  96. package/core/server/api/endpoints/recommendations.js +7 -3
  97. package/core/server/api/endpoints/utils/serializers/input/pages.js +8 -0
  98. package/core/server/api/endpoints/utils/serializers/input/posts.js +9 -1
  99. package/core/server/api/endpoints/utils/serializers/output/members.js +22 -5
  100. package/core/server/api/endpoints/utils/serializers/output/site.js +2 -0
  101. package/core/server/data/exporter/table-lists.js +3 -1
  102. package/core/server/data/migrations/versions/5.63/2023-09-12-11-22-10-add-recommendation-click-events-table.js +8 -0
  103. package/core/server/data/migrations/versions/5.63/2023-09-12-11-22-11-add-recommendation-subscribe-events-table.js +8 -0
  104. package/core/server/data/migrations/versions/5.63/2023-09-13-13-03-10-add-ghost-core-content-integration.js +57 -0
  105. package/core/server/data/migrations/versions/5.63/2023-09-13-13-34-11-add-ghost-core-content-integration-key.js +87 -0
  106. package/core/server/data/schema/fixtures/fixtures.json +7 -0
  107. package/core/server/data/schema/schema.js +12 -0
  108. package/core/server/lib/lexical.js +35 -1
  109. package/core/server/models/post.js +12 -2
  110. package/core/server/models/recommendation-click-event.js +22 -0
  111. package/core/server/models/recommendation-subscribe-event.js +22 -0
  112. package/core/server/services/collections/BookshelfCollectionsRepository.js +67 -5
  113. package/core/server/services/collections/service.js +8 -8
  114. package/core/server/services/members/middleware.js +14 -1
  115. package/core/server/services/members/utils.js +1 -0
  116. package/core/server/services/mentions/WebmentionMetadata.js +38 -1
  117. package/core/server/services/mentions/service.js +2 -1
  118. package/core/server/services/offers/OfferBookshelfRepository.js +230 -0
  119. package/core/server/services/offers/service.js +7 -3
  120. package/core/server/services/public-config/site.js +3 -1
  121. package/core/server/services/recommendations/RecommendationEnablerService.js +28 -0
  122. package/core/server/services/recommendations/RecommendationServiceWrapper.js +45 -2
  123. package/core/server/services/settings/SettingsBREADService.js +6 -1
  124. package/core/server/services/settings/settings-service.js +1 -0
  125. package/core/server/services/settings-helpers/SettingsHelpers.js +7 -0
  126. package/core/server/web/members/app.js +21 -0
  127. package/core/shared/config/defaults.json +2 -2
  128. package/core/shared/settings-cache/public.js +3 -1
  129. package/package.json +161 -160
  130. package/yarn.lock +492 -512
  131. package/components/tryghost-adapter-cache-memory-ttl-5.61.3.tgz +0 -0
  132. package/components/tryghost-adapter-cache-redis-5.61.3.tgz +0 -0
  133. package/components/tryghost-announcement-bar-settings-5.61.3.tgz +0 -0
  134. package/components/tryghost-api-framework-5.61.3.tgz +0 -0
  135. package/components/tryghost-bookshelf-repository-5.61.3.tgz +0 -0
  136. package/components/tryghost-bootstrap-socket-5.61.3.tgz +0 -0
  137. package/components/tryghost-collections-5.61.3.tgz +0 -0
  138. package/components/tryghost-custom-theme-settings-service-5.61.3.tgz +0 -0
  139. package/components/tryghost-data-generator-5.61.3.tgz +0 -0
  140. package/components/tryghost-domain-events-5.61.3.tgz +0 -0
  141. package/components/tryghost-donations-5.61.3.tgz +0 -0
  142. package/components/tryghost-dynamic-routing-events-5.61.3.tgz +0 -0
  143. package/components/tryghost-email-analytics-provider-mailgun-5.61.3.tgz +0 -0
  144. package/components/tryghost-email-content-generator-5.61.3.tgz +0 -0
  145. package/components/tryghost-email-events-5.61.3.tgz +0 -0
  146. package/components/tryghost-email-suppression-list-5.61.3.tgz +0 -0
  147. package/components/tryghost-event-aware-cache-wrapper-5.61.3.tgz +0 -0
  148. package/components/tryghost-express-dynamic-redirects-5.61.3.tgz +0 -0
  149. package/components/tryghost-i18n-5.61.3.tgz +0 -0
  150. package/components/tryghost-in-memory-repository-5.61.3.tgz +0 -0
  151. package/components/tryghost-link-redirects-5.61.3.tgz +0 -0
  152. package/components/tryghost-link-replacer-5.61.3.tgz +0 -0
  153. package/components/tryghost-magic-link-5.61.3.tgz +0 -0
  154. package/components/tryghost-mail-events-5.61.3.tgz +0 -0
  155. package/components/tryghost-mailgun-client-5.61.3.tgz +0 -0
  156. package/components/tryghost-member-events-5.61.3.tgz +0 -0
  157. package/components/tryghost-members-api-5.61.3.tgz +0 -0
  158. package/components/tryghost-members-offers-5.61.3.tgz +0 -0
  159. package/components/tryghost-members-payments-5.61.3.tgz +0 -0
  160. package/components/tryghost-members-ssr-5.61.3.tgz +0 -0
  161. package/components/tryghost-mentions-email-report-5.61.3.tgz +0 -0
  162. package/components/tryghost-model-to-domain-event-interceptor-5.61.3.tgz +0 -0
  163. package/components/tryghost-mw-cache-control-5.61.3.tgz +0 -0
  164. package/components/tryghost-mw-session-from-token-5.61.3.tgz +0 -0
  165. package/components/tryghost-mw-update-user-last-seen-5.61.3.tgz +0 -0
  166. package/components/tryghost-mw-version-match-5.61.3.tgz +0 -0
  167. package/components/tryghost-mw-vhost-5.61.3.tgz +0 -0
  168. package/components/tryghost-nql-filter-expansions-5.61.3.tgz +0 -0
  169. package/components/tryghost-oembed-service-5.61.3.tgz +0 -0
  170. package/components/tryghost-post-events-5.61.3.tgz +0 -0
  171. package/components/tryghost-post-revisions-5.61.3.tgz +0 -0
  172. package/components/tryghost-posts-service-5.61.3.tgz +0 -0
  173. package/components/tryghost-recommendations-5.61.3.tgz +0 -0
  174. package/components/tryghost-referrers-5.61.3.tgz +0 -0
  175. package/components/tryghost-session-service-5.61.3.tgz +0 -0
  176. package/components/tryghost-settings-path-manager-5.61.3.tgz +0 -0
  177. package/components/tryghost-slack-notifications-5.61.3.tgz +0 -0
  178. package/components/tryghost-stats-service-5.61.3.tgz +0 -0
  179. package/components/tryghost-version-notifications-data-service-5.61.3.tgz +0 -0
  180. package/components/tryghost-webmentions-5.61.3.tgz +0 -0
  181. package/core/built/admin/assets/ghost-dark-084169b0e968ef763dfbbf63b253e0c6.css +0 -1
  182. /package/core/built/admin/assets/{chunk.208.dbf172ad32f72f21a5dc.js.LICENSE.txt → chunk.237.9b7032162949850f6c76.js.LICENSE.txt} +0 -0
@@ -8,7 +8,7 @@
8
8
  <title>Ghost Admin</title>
9
9
 
10
10
 
11
- <meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22cdnUrl%22%3A%22%22%2C%22rootURL%22%3A%22%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_JQUERY_INTEGRATION%22%3Atrue%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22version%22%3A%225.61%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22ember-websockets%22%3A%7B%22socketIO%22%3Atrue%7D%2C%22%40sentry%2Fember%22%3A%7B%22disablePerformance%22%3Atrue%2C%22sentry%22%3A%7B%7D%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%7D" />
11
+ <meta name="ghost-admin/config/environment" content="%7B%22modulePrefix%22%3A%22ghost-admin%22%2C%22environment%22%3A%22production%22%2C%22cdnUrl%22%3A%22%22%2C%22rootURL%22%3A%22%22%2C%22locationType%22%3A%22trailing-hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%2C%22Array%22%3Atrue%2C%22String%22%3Atrue%2C%22Function%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_JQUERY_INTEGRATION%22%3Atrue%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22version%22%3A%225.63%22%2C%22name%22%3A%22ghost-admin%22%7D%2C%22ember-simple-auth%22%3A%7B%7D%2C%22ember-websockets%22%3A%7B%22socketIO%22%3Atrue%7D%2C%22%40sentry%2Fember%22%3A%7B%22disablePerformance%22%3Atrue%2C%22sentry%22%3A%7B%7D%7D%2C%22ember-cli-mirage%22%3A%7B%22usingProxy%22%3Afalse%2C%22useDefaultPassthroughs%22%3Atrue%7D%2C%22exportApplicationGlobal%22%3Afalse%2C%22ember-load%22%3A%7B%22loadingIndicatorClass%22%3A%22ember-load-indicator%22%7D%7D" />
12
12
 
13
13
  <meta name="HandheldFriendly" content="True" />
14
14
  <meta name="MobileOptimized" content="320" />
@@ -37,7 +37,7 @@
37
37
  </style>
38
38
 
39
39
  <link integrity="" rel="stylesheet" href="assets/vendor-3e6947aa681f0fb82b193090e520dc73.css">
40
- <link integrity="" rel="stylesheet" href="assets/ghost-8a4e981c272f793157133814ca7c7e84.css" title="light">
40
+ <link integrity="" rel="stylesheet" href="assets/ghost-33664cad4cd6664a8b5fa56e62c5005f.css" title="light">
41
41
 
42
42
 
43
43
  </head>
@@ -56,9 +56,9 @@
56
56
 
57
57
  <div id="ember-basic-dropdown-wormhole"></div>
58
58
 
59
- <script src="assets/vendor-3631184082d609038638c1e169a002e7.js"></script>
60
- <script src="assets/chunk.208.dbf172ad32f72f21a5dc.js"></script>
61
- <script src="assets/chunk.143.da84b3b434141aff0f01.js"></script>
62
- <script src="assets/ghost-54f84395df6a6fb47b37008ded8eba22.js"></script>
59
+ <script src="assets/vendor-f8ce8bd43cf5dad6608f828ab48cee9b.js"></script>
60
+ <script src="assets/chunk.237.9b7032162949850f6c76.js"></script>
61
+ <script src="assets/chunk.143.1c5d21facf1f9b9beef9.js"></script>
62
+ <script src="assets/ghost-7c3f2de2ec83e591ad9f9db5165b2733.js"></script>
63
63
  </body>
64
64
  </html>
@@ -31,6 +31,14 @@ module.exports = function foreach(items, options) {
31
31
  if (Object.values(items).length > 0 && checks.isPost(Object.values(items)[0])) {
32
32
  visibility = visibility || 'all';
33
33
  }
34
+ }
35
+
36
+ if (_.isArray(items) && items.length > 0 && checks.isNewsletter(items[0])) {
37
+ visibility = visibility || 'all';
38
+ } else if (_.isObject(items) && _.isArray(Object.values(items))) {
39
+ if (Object.values(items).length > 0 && checks.isNewsletter(Object.values(items)[0])) {
40
+ visibility = visibility || 'all';
41
+ }
34
42
  }
35
43
  // Exclude items which should not be visible in the theme
36
44
  items = ghostHelperUtils.visibility.filter(items, visibility);
@@ -33,6 +33,9 @@ const RESOURCES = {
33
33
  },
34
34
  tiers: {
35
35
  alias: 'tiersPublic'
36
+ },
37
+ newsletters: {
38
+ alias: 'newslettersPublic'
36
39
  }
37
40
  };
38
41
 
@@ -152,7 +152,7 @@ function getAuthorSchema(metaData, data) {
152
152
  sameAs: trimSameAs(data, 'author'),
153
153
  name: escapeExpression(data.author.name),
154
154
  url: metaData.authorUrl,
155
- image: schemaImageObject(metaData.coverImage),
155
+ image: schemaImageObject(metaData.authorImage) || schemaImageObject(metaData.coverImage),
156
156
  mainEntityOfPage: metaData.authorUrl,
157
157
  description: metaData.metaDescription ?
158
158
  escapeExpression(metaData.metaDescription) :
@@ -3,6 +3,11 @@ function isPost(jsonData) {
3
3
  Object.prototype.hasOwnProperty.call(jsonData, 'title') && Object.prototype.hasOwnProperty.call(jsonData, 'slug');
4
4
  }
5
5
 
6
+ function isNewsletter(jsonData) {
7
+ return Object.prototype.hasOwnProperty.call(jsonData, 'name') &&
8
+ Object.prototype.hasOwnProperty.call(jsonData, 'subscribe_on_signup') && Object.prototype.hasOwnProperty.call(jsonData, 'visibility');
9
+ }
10
+
6
11
  function isPage(jsonData = {}) {
7
12
  return Object.prototype.hasOwnProperty.call(jsonData, 'show_title_and_feature_image');
8
13
  }
@@ -24,6 +29,7 @@ function isNav(jsonData) {
24
29
 
25
30
  module.exports = {
26
31
  isPost,
32
+ isNewsletter,
27
33
  isPage,
28
34
  isTag,
29
35
  isUser,
@@ -0,0 +1,186 @@
1
+ .kg-collection-card {
2
+ width: 100%;
3
+ }
4
+
5
+ .kg-collection-card-title {
6
+ padding: .8rem 0 1.6rem 0;
7
+ font-size: 1.5rem;
8
+ text-transform: uppercase;
9
+ }
10
+
11
+ .kg-collection-card-post {
12
+ display: flex;
13
+ gap: 2rem;
14
+ }
15
+
16
+ .kg-collection-card-img {
17
+ position: relative;
18
+ aspect-ratio: 3/2;
19
+ }
20
+
21
+ .kg-collection-card-img img {
22
+ position: absolute;
23
+ inset: 0;
24
+ width: 100%;
25
+ height: 100%;
26
+ object-fit: cover;
27
+ }
28
+
29
+ .kg-collection-card-content {
30
+ display: flex;
31
+ flex-direction: column;
32
+ font-size: 1.45rem;
33
+ }
34
+
35
+ h2.kg-collection-card-post-title {
36
+ font-size: 1.9rem;
37
+ overflow: hidden;
38
+ display: -webkit-box;
39
+ -webkit-box-orient: vertical;
40
+ -webkit-line-clamp: 2;
41
+ }
42
+
43
+ p.kg-collection-card-post-excerpt {
44
+ margin-top: .8rem;
45
+ overflow: hidden;
46
+ display: -webkit-box;
47
+ -webkit-box-orient: vertical;
48
+ -webkit-line-clamp: 2;
49
+ line-height: 1.4;
50
+ }
51
+
52
+ .kg-collection-card-post-meta {
53
+ display: flex;
54
+ opacity: .5;
55
+ margin-top: .8rem;
56
+ }
57
+
58
+ /* List layout */
59
+
60
+ .kg-collection-card-list {
61
+ display: flex;
62
+ flex-direction: column;
63
+ gap: 2rem;
64
+ }
65
+
66
+ @media (max-width: 767px) {
67
+ .kg-collection-card-list .kg-collection-card-post {
68
+ flex-direction: column;
69
+ }
70
+ }
71
+
72
+ .kg-collection-card-list .kg-collection-card-img {
73
+ flex: 0 0 30%;
74
+ }
75
+
76
+ /* Grid layout */
77
+
78
+ .kg-collection-card-grid {
79
+ display: grid;
80
+ grid-template-columns: repeat(1,minmax(0,1fr));
81
+ gap: 2.4rem;
82
+ }
83
+
84
+ @media (min-width: 640px) {
85
+ .kg-collection-card-grid:not(.columns-1) {
86
+ grid-template-columns: repeat(2,minmax(0,1fr));
87
+ }
88
+ }
89
+
90
+ @media (min-width: 1024px) {
91
+ .kg-collection-card-grid:not(.columns-1):not(.columns-2) {
92
+ grid-template-columns: repeat(3,minmax(0,1fr));
93
+ gap: 3.2rem
94
+ }
95
+
96
+ .kg-collection-card-grid.columns-1 {
97
+ gap: 4.8rem
98
+ }
99
+
100
+ .kg-collection-card-grid.columns-2 {
101
+ gap: 4rem
102
+ }
103
+ }
104
+
105
+ @media (min-width: 1280px) {
106
+ .kg-collection-card-grid:not(.columns-1):not(.columns-2):not(.columns-3) {
107
+ grid-template-columns: repeat(4,minmax(0,1fr));
108
+ }
109
+ }
110
+
111
+ .kg-collection-card-grid .kg-collection-card-post {
112
+ flex-direction: column;
113
+ gap: 1.2rem;
114
+ }
115
+
116
+ @media (min-width: 1024px) {
117
+ .kg-collection-card-grid.columns-1 .kg-collection-card-post {
118
+ gap: 2rem
119
+ }
120
+
121
+ .kg-collection-card-grid.columns-2 .kg-collection-card-post {
122
+ gap: 1.6rem
123
+ }
124
+ }
125
+
126
+ .kg-collection-card-grid.columns-1 .kg-collection-card-img,
127
+ .kg-collection-card-grid.columns-2 .kg-collection-card-img {
128
+ aspect-ratio: 16/9;
129
+ }
130
+
131
+ .kg-collection-card-grid .kg-collection-card-content {
132
+ font-size: 1.5rem;
133
+ }
134
+
135
+ @media (min-width: 640px) {
136
+ .kg-collection-card-grid .kg-collection-card-content {
137
+ font-size: 1.6rem;
138
+ }
139
+ }
140
+
141
+ @media (min-width: 1024px) {
142
+ .kg-collection-card-grid.columns-1 .kg-collection-card-content {
143
+ font-size: 1.8rem;
144
+ }
145
+
146
+ .kg-collection-card-grid.columns-3 .kg-collection-card-content,
147
+ .kg-collection-card-grid.columns-4 .kg-collection-card-content {
148
+ font-size: 1.5rem;
149
+ }
150
+ }
151
+
152
+ .kg-collection-card-grid h2.kg-collection-card-post-title {
153
+ font-size: 1.7rem;
154
+ }
155
+
156
+ @media (min-width: 640px) {
157
+ .kg-collection-card-grid h2.kg-collection-card-post-title {
158
+ font-size: 1.9rem;
159
+ }
160
+
161
+ .kg-collection-card-grid.columns-1 h2.kg-collection-card-post-title {
162
+ font-size: 2.4rem;
163
+ }
164
+ }
165
+
166
+ /* @media (min-width: 768px) {
167
+ .kg-collection-card-grid.columns-1 h2.kg-collection-card-post-title {
168
+ font-size: 2.4rem;
169
+ }
170
+ } */
171
+
172
+ @media (min-width: 1024px) {
173
+ .kg-collection-card-grid.columns-1 h2.kg-collection-card-post-title {
174
+ font-size: 3.6rem;
175
+ }
176
+
177
+ .kg-collection-card-grid.columns-2 h2.kg-collection-card-post-title {
178
+ font-size: 2.4rem;
179
+ }
180
+ }
181
+
182
+ @media (min-width: 1280px) {
183
+ .kg-collection-card-grid.columns-4 h2.kg-collection-card-post-title {
184
+ font-size: 1.7rem;
185
+ }
186
+ }
@@ -71,7 +71,7 @@
71
71
  }
72
72
 
73
73
  .kg-header-card.kg-style-image h2.kg-header-card-heading,
74
- .kg-header-card.kg-style-image h3.kg-header-card-subheading,
74
+ .kg-header-card.kg-style-image .kg-header-card-subheading,
75
75
  .kg-header-card.kg-style-image.kg-v2 .kg-header-card-button {
76
76
  z-index: 999;
77
77
  }
@@ -112,26 +112,22 @@
112
112
 
113
113
  .kg-header-card h2.kg-header-card-heading {
114
114
  margin: 0;
115
- font-size: clamp(2.8rem, 4vw, 4rem);
115
+ font-size: clamp(2.4rem, 4vw, 3.6rem);
116
116
  font-weight: 700;
117
117
  line-height: 1em;
118
118
  letter-spacing: -0.01em;
119
119
  }
120
120
 
121
121
  .kg-header-card.kg-width-wide h2.kg-header-card-heading {
122
- font-size: clamp(2.8rem, 5vw, 5.2rem);
122
+ font-size: clamp(2.4rem, 5vw, 4.8rem);
123
123
  }
124
124
 
125
125
  .kg-header-card.kg-width-full h2.kg-header-card-heading {
126
- font-size: clamp(3.6rem, 5.6vw, 6.4rem);
126
+ font-size: clamp(2.8rem, 5.6vw, 6rem);
127
127
  }
128
128
 
129
129
  .kg-header-card.kg-width-full.kg-layout-split h2.kg-header-card-heading {
130
- font-size: clamp(3.2rem, 4vw, 5.6rem);
131
- }
132
-
133
- .kg-header-card.kg-width-full.kg-layout-split.kg-content-wide h2.kg-header-card-heading {
134
- font-size: clamp(2.8rem, 4vw, 5.2rem);
130
+ font-size: clamp(2.8rem, 4vw, 4.8rem);
135
131
  }
136
132
 
137
133
  /* Subheading */
@@ -140,33 +136,33 @@
140
136
  margin: 0 0 2em;
141
137
  }
142
138
 
143
- .kg-header-card h3.kg-header-card-subheading {
139
+ .kg-header-card .kg-header-card-subheading {
144
140
  max-width: 40em;
145
141
  margin: 0;
146
142
  font-size: clamp(1.05em, 2vw, 2rem);
147
143
  font-weight: 500;
148
- line-height: 1.4em;
144
+ line-height: 1.2em;
149
145
  }
150
146
 
151
- .kg-header-card h2 + h3.kg-header-card-subheading {
147
+ .kg-header-card h2 + .kg-header-card-subheading {
152
148
  margin: 0.6em 0 0;
153
149
  }
154
150
 
155
- .kg-header-card h3.kg-header-card-subheading strong {
151
+ .kg-header-card .kg-header-card-subheading strong {
156
152
  font-weight: 600;
157
153
  }
158
154
 
159
- .kg-header-card.kg-width-wide h3.kg-header-card-subheading {
160
- font-size: clamp(1.05em, 2vw, 2.4rem);
155
+ .kg-header-card.kg-width-wide .kg-header-card-subheading {
156
+ font-size: clamp(1.05em, 2vw, 2.2rem);
161
157
  }
162
158
 
163
- .kg-header-card.kg-width-full h3.kg-header-card-subheading:not(.kg-layout-split h3.kg-header-card-subheading) {
159
+ .kg-header-card.kg-width-full .kg-header-card-subheading:not(.kg-layout-split .kg-header-card-subheading) {
164
160
  max-width: min(65vmax, 1200px);
165
- font-size: clamp(1.05em, 2vw, 2.6rem);
161
+ font-size: clamp(1.05em, 2vw, 2.4rem);
166
162
  }
167
163
 
168
- .kg-header-card.kg-width-full.kg-layout-split h3.kg-header-card-subheading {
169
- font-size: clamp(1.05em, 2vw, 2.4rem);
164
+ .kg-header-card.kg-width-full.kg-layout-split .kg-header-card-subheading {
165
+ font-size: clamp(1.05em, 2vw, 2.2rem);
170
166
  }
171
167
 
172
168
  .kg-header-card.kg-v2 .kg-header-card-button {
@@ -194,7 +190,7 @@
194
190
  }
195
191
 
196
192
  .kg-header-card.kg-v2 h2 + .kg-header-card-button,
197
- .kg-header-card.kg-v2 h3 + .kg-header-card-button {
193
+ .kg-header-card.kg-v2 p + .kg-header-card-button {
198
194
  margin: 1.5em 0 0;
199
195
  }
200
196
 
@@ -207,7 +203,7 @@
207
203
  }
208
204
 
209
205
  .kg-header-card.kg-v2.kg-width-wide h2 + .kg-header-card-button,
210
- .kg-header-card.kg-v2.kg-width-wide h3 + .kg-header-card-button {
206
+ .kg-header-card.kg-v2.kg-width-wide p + .kg-header-card-button {
211
207
  margin-top: 1.75em;
212
208
  }
213
209
 
@@ -216,7 +212,7 @@
216
212
  }
217
213
 
218
214
  .kg-header-card.kg-v2.kg-width-full h2 + .kg-header-card-button,
219
- .kg-header-card.kg-v2.kg-width-full h3 + .kg-header-card-button {
215
+ .kg-header-card.kg-v2.kg-width-full p + .kg-header-card-button {
220
216
  margin-top: 2em;
221
217
  }
222
218
 
@@ -236,7 +232,7 @@
236
232
  padding: min(9.6vmax, 180px) 0;
237
233
  }
238
234
 
239
- .kg-header-card.kg-width-full h3.kg-header-card-subheading:not(.kg-layout-split h3.kg-header-card-subheading) {
235
+ .kg-header-card.kg-width-full .kg-header-card-subheading:not(.kg-layout-split .kg-header-card-subheading) {
240
236
  max-width: unset;
241
237
  }
242
238
 
@@ -64,7 +64,7 @@
64
64
  }
65
65
 
66
66
  .kg-signup-card.kg-style-image h2.kg-signup-card-heading,
67
- .kg-signup-card.kg-style-image h3.kg-signup-card-subheading,
67
+ .kg-signup-card.kg-style-image .kg-signup-card-subheading,
68
68
  .kg-signup-card.kg-style-image .kg-signup-card-button {
69
69
  z-index: 999;
70
70
  }
@@ -105,26 +105,22 @@
105
105
 
106
106
  .kg-signup-card h2.kg-signup-card-heading {
107
107
  margin: 0;
108
- font-size: clamp(2.8rem, 4vw, 4rem);
108
+ font-size: clamp(2.4rem, 4vw, 3.6rem);
109
109
  font-weight: 700;
110
110
  line-height: 1em;
111
111
  letter-spacing: -0.01em;
112
112
  }
113
113
 
114
114
  .kg-signup-card.kg-width-wide h2.kg-signup-card-heading {
115
- font-size: clamp(2.8rem, 5vw, 5.2rem);
115
+ font-size: clamp(2.4rem, 5vw, 4.8rem);
116
116
  }
117
117
 
118
118
  .kg-signup-card.kg-width-full h2.kg-signup-card-heading {
119
- font-size: clamp(3.6rem, 5.6vw, 6.4rem);
119
+ font-size: clamp(2.8rem, 5.6vw, 6rem);
120
120
  }
121
121
 
122
122
  .kg-signup-card.kg-width-full.kg-layout-split h2.kg-signup-card-heading {
123
- font-size: clamp(3.2rem, 4vw, 5.6rem);
124
- }
125
-
126
- .kg-signup-card.kg-width-full.kg-layout-split.kg-content-wide h2.kg-signup-card-heading {
127
- font-size: clamp(2.8rem, 4vw, 5.2rem);
123
+ font-size: clamp(2.8rem, 4vw, 4.8rem);
128
124
  }
129
125
 
130
126
  /* Subheading */
@@ -133,33 +129,33 @@
133
129
  margin: 0 0 2em;
134
130
  }
135
131
 
136
- .kg-signup-card h3.kg-signup-card-subheading {
132
+ .kg-signup-card .kg-signup-card-subheading {
137
133
  max-width: 40em;
138
134
  margin: 0;
139
135
  font-size: clamp(1.05em, 2vw, 2rem);
140
136
  font-weight: 500;
141
- line-height: 1.4em;
137
+ line-height: 1.2em;
142
138
  }
143
139
 
144
- .kg-signup-card h2 + h3.kg-signup-card-subheading {
140
+ .kg-signup-card h2 + .kg-signup-card-subheading {
145
141
  margin: 0.6em 0 0;
146
142
  }
147
143
 
148
- .kg-signup-card h3.kg-signup-card-subheading strong {
144
+ .kg-signup-card .kg-signup-card-subheading strong {
149
145
  font-weight: 600;
150
146
  }
151
147
 
152
- .kg-signup-card.kg-width-wide h3.kg-signup-card-subheading {
153
- font-size: clamp(1.05em, 2vw, 2.4rem);
148
+ .kg-signup-card.kg-width-wide .kg-signup-card-subheading {
149
+ font-size: clamp(1.05em, 2vw, 2.2rem);
154
150
  }
155
151
 
156
- .kg-signup-card.kg-width-full h3.kg-signup-card-subheading:not(.kg-layout-split h3.kg-signup-card-subheading) {
152
+ .kg-signup-card.kg-width-full .kg-signup-card-subheading:not(.kg-layout-split .kg-signup-card-subheading) {
157
153
  max-width: min(65vmax, 1200px);
158
- font-size: clamp(1.05em, 2vw, 2.6rem);
154
+ font-size: clamp(1.05em, 2vw, 2.4rem);
159
155
  }
160
156
 
161
- .kg-signup-card.kg-width-full.kg-layout-split h3.kg-signup-card-subheading {
162
- font-size: clamp(1.05em, 2vw, 2.4rem);
157
+ .kg-signup-card.kg-width-full.kg-layout-split .kg-signup-card-subheading {
158
+ font-size: clamp(1.05em, 2vw, 2.2rem);
163
159
  }
164
160
 
165
161
  /* Subscribe form */
@@ -238,6 +234,7 @@
238
234
  text-overflow: ellipsis;
239
235
  border-radius: 3px;
240
236
  transition: opacity .2s ease;
237
+ cursor: pointer;
241
238
  }
242
239
 
243
240
  .kg-signup-card-button.kg-style-accent {
@@ -245,7 +242,7 @@
245
242
  }
246
243
 
247
244
  .kg-signup-card h2 + .kg-signup-card-button,
248
- .kg-signup-card h3 + .kg-signup-card-button {
245
+ .kg-signup-card p + .kg-signup-card-button {
249
246
  margin: 1.5em 0 0;
250
247
  }
251
248
 
@@ -258,7 +255,7 @@
258
255
  }
259
256
 
260
257
  .kg-signup-card.kg-width-wide h2 + .kg-signup-card-button,
261
- .kg-signup-card.kg-width-wide h3 + .kg-signup-card-button {
258
+ .kg-signup-card.kg-width-wide p + .kg-signup-card-button {
262
259
  margin-top: 1.75em;
263
260
  }
264
261
 
@@ -267,7 +264,7 @@
267
264
  }
268
265
 
269
266
  .kg-signup-card.kg-width-full h2 + .kg-signup-card-button,
270
- .kg-signup-card.kg-width-full h3 + .kg-signup-card-button {
267
+ .kg-signup-card.kg-width-full p + .kg-signup-card-button {
271
268
  margin-top: 2em;
272
269
  }
273
270
 
@@ -347,7 +344,7 @@
347
344
  padding: min(9.6vmax, 180px) 0;
348
345
  }
349
346
 
350
- .kg-signup-card.kg-width-full h3.kg-signup-card-subheading:not(.kg-layout-split h3.kg-signup-card-subheading) {
347
+ .kg-signup-card.kg-width-full .kg-signup-card-subheading:not(.kg-layout-split .kg-signup-card-subheading) {
351
348
  max-width: unset;
352
349
  }
353
350
 
@@ -4,9 +4,7 @@ const serveStatic = require('../../../shared/express').static;
4
4
 
5
5
  const fs = require('fs-extra');
6
6
  const path = require('path');
7
- const moment = require('moment');
8
7
  const tpl = require('@tryghost/tpl');
9
- const logging = require('@tryghost/logging');
10
8
  const errors = require('@tryghost/errors');
11
9
  const constants = require('@tryghost/constants');
12
10
  const urlUtils = require('../../../shared/url-utils');
@@ -127,16 +125,11 @@ class LocalStorageBase extends StorageBase {
127
125
  const {storagePath, errorMessages} = this;
128
126
 
129
127
  return function serveStaticContent(req, res, next) {
130
- const startedAtMoment = moment();
131
-
132
128
  return serveStatic(
133
129
  storagePath,
134
130
  {
135
131
  maxAge: constants.ONE_YEAR_MS,
136
- fallthrough: false,
137
- onEnd: () => {
138
- logging.info('LocalStorageBase.serve', req.path, moment().diff(startedAtMoment, 'ms') + 'ms');
139
- }
132
+ fallthrough: false
140
133
  }
141
134
  )(req, res, (err) => {
142
135
  if (err) {
@@ -9,16 +9,55 @@ module.exports = {
9
9
  },
10
10
  options: [
11
11
  'limit',
12
- 'fields',
13
- 'filter',
14
12
  'order',
15
- 'debug',
16
13
  'page'
17
14
  ],
18
15
  permissions: true,
19
16
  validation: {},
20
- async query() {
21
- return await recommendations.controller.listRecommendations();
17
+ async query(frame) {
18
+ return await recommendations.controller.listRecommendations(frame);
19
+ }
20
+ },
21
+
22
+ trackClicked: {
23
+ headers: {
24
+ cacheInvalidate: false
25
+ },
26
+ options: [
27
+ 'id'
28
+ ],
29
+ validation: {
30
+ options: {
31
+ id: {
32
+ required: true
33
+ }
34
+ }
35
+ },
36
+ permissions: true,
37
+ statusCode: 204,
38
+ async query(frame) {
39
+ await recommendations.controller.trackClicked(frame);
40
+ }
41
+ },
42
+
43
+ trackSubscribed: {
44
+ headers: {
45
+ cacheInvalidate: false
46
+ },
47
+ options: [
48
+ 'id'
49
+ ],
50
+ validation: {
51
+ options: {
52
+ id: {
53
+ required: true
54
+ }
55
+ }
56
+ },
57
+ permissions: true,
58
+ statusCode: 204,
59
+ async query(frame) {
60
+ await recommendations.controller.trackSubscribed(frame);
22
61
  }
23
62
  }
24
63
  };
@@ -7,11 +7,15 @@ module.exports = {
7
7
  headers: {
8
8
  cacheInvalidate: false
9
9
  },
10
- options: [],
10
+ options: [
11
+ 'limit',
12
+ 'page',
13
+ 'include'
14
+ ],
11
15
  permissions: true,
12
16
  validation: {},
13
- async query() {
14
- return await recommendations.controller.listRecommendations();
17
+ async query(frame) {
18
+ return await recommendations.controller.listRecommendations(frame);
15
19
  }
16
20
  },
17
21
 
@@ -6,6 +6,8 @@ const slugFilterOrder = require('./utils/slug-filter-order');
6
6
  const localUtils = require('../../index');
7
7
  const postsMetaSchema = require('../../../../../data/schema').tables.posts_meta;
8
8
  const clean = require('./utils/clean');
9
+ const labs = require('../../../../../../shared/labs');
10
+ const lexical = require('../../../../../lib/lexical');
9
11
 
10
12
  function removeSourceFormats(frame) {
11
13
  if (frame.options.formats?.includes('mobiledoc') || frame.options.formats?.includes('lexical')) {
@@ -133,6 +135,12 @@ module.exports = {
133
135
 
134
136
  if (frame.options.source === 'html' && !_.isEmpty(html)) {
135
137
  frame.data.pages[0].mobiledoc = JSON.stringify(mobiledoc.htmlToMobiledocConverter(html));
138
+
139
+ // normally we don't allow both mobiledoc+lexical but the model layer will remove lexical
140
+ // if mobiledoc is already present to avoid migrating formats outside of an explicit conversion
141
+ if (labs.isSet('lexicalEditor')) {
142
+ frame.data.pages[0].lexical = JSON.stringify(lexical.htmlToLexicalConverter(html));
143
+ }
136
144
  }
137
145
  }
138
146
 
@@ -6,6 +6,8 @@ const localUtils = require('../../index');
6
6
  const mobiledoc = require('../../../../../lib/mobiledoc');
7
7
  const postsMetaSchema = require('../../../../../data/schema').tables.posts_meta;
8
8
  const clean = require('./utils/clean');
9
+ const labs = require('../../../../../../shared/labs');
10
+ const lexical = require('../../../../../lib/lexical');
9
11
 
10
12
  function removeSourceFormats(frame) {
11
13
  if (frame.options.formats?.includes('mobiledoc') || frame.options.formats?.includes('lexical')) {
@@ -32,7 +34,7 @@ function defaultRelations(frame) {
32
34
  // Apply same mapping as content API
33
35
  mapWithRelated(frame);
34
36
 
35
- // Addditional defaults for admin API
37
+ // Additional defaults for admin API
36
38
  if (frame.options.withRelated) {
37
39
  return;
38
40
  }
@@ -167,6 +169,12 @@ module.exports = {
167
169
 
168
170
  if (frame.options.source === 'html' && !_.isEmpty(html)) {
169
171
  frame.data.posts[0].mobiledoc = JSON.stringify(mobiledoc.htmlToMobiledocConverter(html));
172
+
173
+ // normally we don't allow both mobiledoc+lexical but the model layer will remove lexical
174
+ // if mobiledoc is already present to avoid migrating formats outside of an explicit conversion
175
+ if (labs.isSet('lexicalEditor')) {
176
+ frame.data.posts[0].lexical = JSON.stringify(lexical.htmlToLexicalConverter(html));
177
+ }
170
178
  }
171
179
  }
172
180