ghost 4.23.0 → 4.26.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.
- package/.eslintrc.js +39 -0
- package/content/themes/casper/assets/built/casper.js +1 -1
- package/content/themes/casper/assets/built/casper.js.map +1 -1
- package/content/themes/casper/assets/built/global.css +1 -1
- package/content/themes/casper/assets/built/global.css.map +1 -1
- package/content/themes/casper/assets/built/screen.css +1 -1
- package/content/themes/casper/assets/built/screen.css.map +1 -1
- package/content/themes/casper/assets/css/global.css +6 -1
- package/content/themes/casper/assets/css/screen.css +50 -215
- package/content/themes/casper/default.hbs +2 -2
- package/content/themes/casper/package.json +3 -2
- package/content/themes/casper/post.hbs +1 -1
- package/content/themes/casper/yarn.lock +173 -123
- package/core/app.js +20 -5
- package/core/boot.js +77 -36
- package/core/bridge.js +10 -10
- package/core/built/assets/ghost-dark-ef86e3bc7f0fb83d39d3d6a49bff8dd5.css +1 -0
- package/core/built/assets/ghost.min-57c1e677f42d596942d317ce93e8a62c.css +1 -0
- package/core/built/assets/{ghost.min-cccc107e881b74c7aaf1a73e1e5e0dee.js → ghost.min-f3c6886e191d34450e9ffca0c8fa056e.js} +543 -618
- package/core/built/assets/icons/audio-upload.svg +8 -0
- package/core/built/assets/{vendor.min-c9002845b6c30ac978abdadde9f33d7c.js → vendor.min-b6b8d2a31d61830c2d8f65c5ba54236a.js} +2656 -2118
- package/core/frontend/apps/amp/lib/helpers/amp_content.js +2 -2
- package/core/frontend/apps/amp/lib/views/amp.hbs +75 -0
- package/core/frontend/apps/private-blogging/index.js +1 -1
- package/core/frontend/helpers/url.js +18 -1
- package/core/frontend/services/apps/index.js +1 -1
- package/core/frontend/services/apps/loader.js +3 -3
- package/core/frontend/services/card-assets/index.js +0 -12
- package/core/frontend/services/card-assets/service.js +22 -21
- package/core/frontend/services/helpers/handlebars.js +1 -1
- package/core/frontend/services/theme-engine/middleware/ensure-active-theme.js +34 -0
- package/core/frontend/services/theme-engine/middleware/index.js +6 -0
- package/core/frontend/services/theme-engine/middleware/update-global-template-options.js +116 -0
- package/core/frontend/services/theme-engine/middleware/update-local-template-data.js +9 -0
- package/core/frontend/services/theme-engine/middleware/update-local-template-options.js +57 -0
- package/core/frontend/src/cards/css/audio.css +186 -0
- package/core/frontend/src/cards/css/blockquote.css +27 -0
- package/core/frontend/src/cards/css/bookmark.css +7 -0
- package/core/frontend/src/cards/css/button.css +4 -0
- package/core/frontend/src/cards/css/callout.css +23 -15
- package/core/frontend/src/cards/css/gallery.css +13 -3
- package/core/frontend/src/cards/css/toggle.css +48 -15
- package/core/frontend/src/cards/js/audio.js +137 -0
- package/core/frontend/web/middleware/error-handler.js +93 -0
- package/core/frontend/web/middleware/handle-image-sizes.js +3 -6
- package/core/frontend/web/middleware/index.js +1 -0
- package/core/frontend/web/middleware/serve-public-file.js +25 -8
- package/core/frontend/web/site.js +2 -5
- package/core/server/adapters/scheduling/SchedulingDefault.js +2 -2
- package/core/server/adapters/storage/LocalStorageBase.js +2 -2
- package/core/server/api/canary/db.js +2 -2
- package/core/server/api/canary/media.js +3 -2
- package/core/server/api/canary/oembed.js +16 -1
- package/core/server/api/canary/session.js +1 -1
- package/core/server/api/canary/slugs.js +1 -1
- package/core/server/api/canary/utils/permissions.js +2 -2
- package/core/server/api/canary/utils/serializers/output/config.js +2 -6
- package/core/server/api/v2/db.js +2 -2
- package/core/server/api/v2/session.js +1 -1
- package/core/server/api/v2/slugs.js +1 -1
- package/core/server/api/v2/utils/permissions.js +2 -2
- package/core/server/api/v3/db.js +2 -2
- package/core/server/api/v3/session.js +1 -1
- package/core/server/api/v3/slugs.js +1 -1
- package/core/server/api/v3/utils/permissions.js +2 -2
- package/core/server/data/db/state-manager.js +4 -4
- package/core/server/data/exporter/export-filename.js +1 -1
- package/core/server/data/importer/handlers/json.js +1 -1
- package/core/server/data/importer/import-manager.js +1 -1
- package/core/server/data/importer/importers/data/base.js +1 -1
- package/core/server/data/migrations/utils.js +2 -2
- package/core/server/data/migrations/versions/1.25/1-update-koenig-beta-html.js +1 -0
- package/core/server/data/migrations/versions/3.1/08-add-uuid-values-to-members.js +1 -0
- package/core/server/data/migrations/versions/3.22/02-settings-key-renames.js +2 -0
- package/core/server/data/migrations/versions/3.22/05-migrate-members-subscription-settings.js +3 -0
- package/core/server/data/migrations/versions/3.22/06-migrate-stripe-connect-settings.js +2 -0
- package/core/server/data/migrations/versions/3.23/01-migrate-bulk-email-settings.js +1 -0
- package/core/server/data/migrations/versions/3.29/01-remove-duplicate-subscriptions.js +2 -0
- package/core/server/data/migrations/versions/3.29/02-remove-duplicate-customers.js +2 -0
- package/core/server/data/migrations/versions/3.38/04-populate-recipient-filter-column.js +2 -0
- package/core/server/data/migrations/versions/4.0/01-update-mobiledoc.js +2 -0
- package/core/server/data/migrations/versions/4.0/03-populate-status-column-for-members.js +4 -0
- package/core/server/data/migrations/versions/4.0/06-populate-members-subscribe-events-table.js +1 -0
- package/core/server/data/migrations/versions/4.0/17-populate-members-status-events-table.js +1 -0
- package/core/server/data/migrations/versions/4.0/18-transform-urls-absolute-to-transform-ready.js +5 -0
- package/core/server/data/migrations/versions/4.0/22-solve-orphaned-webhooks.js +1 -0
- package/core/server/data/migrations/versions/4.0/23-regenerate-posts-html.js +1 -0
- package/core/server/data/migrations/versions/4.0/25-populate-members-paid-subscription-events-table.js +2 -1
- package/core/server/data/migrations/versions/4.12/02-fix-member-statuses.js +1 -0
- package/core/server/data/migrations/versions/4.14/01-fix-comped-member-statuses.js +3 -0
- package/core/server/data/migrations/versions/4.14/02-fix-free-members-status-events.js +1 -0
- package/core/server/data/migrations/versions/4.20/05-remove-not-null-constraint-from-portal-title.js +2 -0
- package/core/server/data/migrations/versions/4.23/01-truncate-offer-names.js +1 -0
- package/core/server/data/migrations/versions/4.3/04-attach-members-to-product.js +1 -0
- package/core/server/data/migrations/versions/4.4/01-restore-free-members-signup-setting-from-backup.js +1 -0
- package/core/server/data/migrations/versions/4.6/01-remove-comped-status.js +1 -0
- package/core/server/data/migrations/versions/4.8/04-migrate-show-newsletter-header-setting.js +1 -0
- package/core/server/data/migrations/versions/4.9/05-fix-missed-mobiledoc-url-transforms.js +1 -0
- package/core/server/data/migrations/versions/4.9/06-add-comped-status.js +1 -0
- package/core/server/data/migrations/versions/4.9/07-update-comped-members-status-events.js +1 -0
- package/core/server/data/schema/commands.js +2 -2
- package/core/server/ghost-server.js +2 -2
- package/core/server/lib/image/image-size.js +2 -2
- package/core/server/models/base/listeners.js +2 -2
- package/core/server/models/member-email-change-event.js +2 -2
- package/core/server/models/member-login-event.js +2 -2
- package/core/server/models/member-paid-subscription-event.js +3 -3
- package/core/server/models/member-payment-event.js +3 -3
- package/core/server/models/member-product-event.js +6 -6
- package/core/server/models/member-status-event.js +5 -3
- package/core/server/models/member-subscribe-event.js +9 -3
- package/core/server/models/relations/authors.js +1 -1
- package/core/server/models/settings.js +1 -1
- package/core/server/notify.js +1 -2
- package/core/server/services/auth/passwordreset.js +1 -1
- package/core/server/services/auth/setup.js +1 -1
- package/core/server/services/email-analytics/jobs/index.js +1 -1
- package/core/server/services/mega/mega.js +6 -4
- package/core/server/services/mega/template.js +47 -17
- package/core/server/services/members/api.js +22 -0
- package/core/server/services/members/config.js +1 -1
- package/core/server/services/members/emails/signup-paid.js +168 -0
- package/core/server/services/members/service.js +6 -2
- package/core/server/services/members/stripe-connect.js +4 -2
- package/core/server/services/nft-oembed.js +7 -2
- package/core/server/services/oembed.js +15 -3
- package/core/server/services/permissions/can-this.js +1 -1
- package/core/server/services/redirects/api.js +20 -25
- package/core/server/services/redirects/index.js +18 -10
- package/core/server/services/redirects/utils.js +14 -0
- package/core/server/services/redirects/validation.js +10 -0
- package/core/server/services/route-settings/default-settings-manager.js +1 -1
- package/core/server/services/route-settings/index.js +40 -17
- package/core/server/services/route-settings/route-settings.js +120 -115
- package/core/server/services/route-settings/settings-loader.js +18 -36
- package/core/server/services/route-settings/yaml-parser.js +1 -1
- package/core/server/services/slack.js +1 -1
- package/core/server/services/themes/activation-bridge.js +3 -3
- package/core/server/services/themes/storage.js +2 -2
- package/core/server/services/twitter-embed.js +81 -0
- package/core/server/services/url/LocalFileCache.js +75 -0
- package/core/server/services/url/UrlService.js +15 -47
- package/core/server/services/url/index.js +17 -4
- package/core/server/services/xmlrpc.js +2 -2
- package/core/server/web/admin/app.js +2 -5
- package/core/server/web/admin/controller.js +35 -12
- package/core/server/web/admin/middleware/redirect-admin-urls.js +15 -0
- package/core/server/web/admin/views/default-prod.html +4 -4
- package/core/server/web/admin/views/default.html +4 -4
- package/core/server/web/api/canary/admin/app.js +0 -3
- package/core/server/web/api/canary/admin/middleware.js +1 -1
- package/core/server/web/api/canary/content/app.js +0 -3
- package/core/server/web/api/v2/admin/app.js +0 -3
- package/core/server/web/api/v2/admin/middleware.js +1 -1
- package/core/server/web/api/v2/content/app.js +0 -3
- package/core/server/web/api/v3/admin/app.js +0 -3
- package/core/server/web/api/v3/admin/middleware.js +1 -1
- package/core/server/web/api/v3/content/app.js +0 -3
- package/core/server/web/members/app.js +0 -3
- package/core/server/web/oauth/app.js +0 -4
- package/core/server/web/parent/app.js +2 -13
- package/core/server/web/parent/backend.js +2 -0
- package/core/server/web/shared/middleware/error-handler.js +57 -162
- package/core/server/web/shared/middleware/index.js +0 -4
- package/core/shared/config/defaults.json +7 -1
- package/core/shared/express.js +1 -1
- package/core/shared/labs.js +12 -7
- package/core/shared/sentry.js +1 -1
- package/package.json +41 -40
- package/yarn.lock +799 -948
- package/content/themes/casper/assets/js/gallery-card.js +0 -24
- package/core/built/assets/ghost-dark-42cf6e0c730578940ec069bda45aea41.css +0 -1
- package/core/built/assets/ghost.min-fcf6a0738421f86c47c55f20d00c5ba9.css +0 -1
- package/core/frontend/services/theme-engine/middleware.js +0 -209
- package/core/server/web/shared/middleware/maintenance.js +0 -25
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
.kg-audio-card {
|
|
2
|
+
margin-top: 7vmin;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.kg-audio-player-container button {
|
|
6
|
+
padding: 0;
|
|
7
|
+
border: 0;
|
|
8
|
+
background: transparent;
|
|
9
|
+
cursor: pointer;
|
|
10
|
+
outline: none;
|
|
11
|
+
width: 40px;
|
|
12
|
+
height: 40px;
|
|
13
|
+
float: left;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.kg-audio-player-container {
|
|
17
|
+
position: relative;
|
|
18
|
+
/* margin: 0 2.5% auto 2.5%; */
|
|
19
|
+
width: 100%;
|
|
20
|
+
/* max-width: 500px; */
|
|
21
|
+
height: 132px;
|
|
22
|
+
background: #fff;
|
|
23
|
+
font-family: Arial, Helvetica, sans-serif;
|
|
24
|
+
--seek-before-width: 0%;
|
|
25
|
+
--volume-before-width: 100%;
|
|
26
|
+
--buffered-width: 0%;
|
|
27
|
+
letter-spacing: -0.5px;
|
|
28
|
+
}
|
|
29
|
+
.kg-audio-player-container::before {
|
|
30
|
+
position: absolute;
|
|
31
|
+
content: '';
|
|
32
|
+
width: calc(100% + 4px);
|
|
33
|
+
height: calc(100% + 4px);
|
|
34
|
+
left: -2px;
|
|
35
|
+
top: -2px;
|
|
36
|
+
background: linear-gradient(to left, #007db5, #ff8a00);
|
|
37
|
+
z-index: -1;
|
|
38
|
+
}
|
|
39
|
+
.kg-audio-player-container p {
|
|
40
|
+
position: absolute;
|
|
41
|
+
top: -18px;
|
|
42
|
+
right: 5%;
|
|
43
|
+
padding: 0 5px;
|
|
44
|
+
margin: 0;
|
|
45
|
+
font-size: 24px;
|
|
46
|
+
background: #fff;
|
|
47
|
+
}
|
|
48
|
+
.kg-audio-play-icon {
|
|
49
|
+
margin: 20px 2.5% 10px 2.5%;
|
|
50
|
+
}
|
|
51
|
+
.kg-audio-player-container path {
|
|
52
|
+
stroke: #007db5;
|
|
53
|
+
}
|
|
54
|
+
.kg-audio-duration,
|
|
55
|
+
.kg-audio-current-time {
|
|
56
|
+
display: inline-block;
|
|
57
|
+
width: 37px;
|
|
58
|
+
text-align: center;
|
|
59
|
+
font-size: 20px;
|
|
60
|
+
margin: 28.5px 0 18.5px 0;
|
|
61
|
+
float: left;
|
|
62
|
+
}
|
|
63
|
+
.kg-audio-player-container output {
|
|
64
|
+
display: inline-block;
|
|
65
|
+
width: 32px;
|
|
66
|
+
text-align: center;
|
|
67
|
+
font-size: 20px;
|
|
68
|
+
margin: 10px 2.5% 0 5%;
|
|
69
|
+
float: left;
|
|
70
|
+
clear: left;
|
|
71
|
+
}
|
|
72
|
+
.kg-audio-volume-slider {
|
|
73
|
+
margin: 10px 2.5% !important;
|
|
74
|
+
width: 58% !important;
|
|
75
|
+
}
|
|
76
|
+
.kg-audio-volume-slider::-webkit-slider-runnable-track {
|
|
77
|
+
background: rgba(0, 125, 181, 0.6) !important;
|
|
78
|
+
}
|
|
79
|
+
.kg-audio-volume-slider::-moz-range-track {
|
|
80
|
+
background: rgba(0, 125, 181, 0.6) !important;
|
|
81
|
+
}
|
|
82
|
+
.kg-audio-volume-slider::-ms-fill-upper {
|
|
83
|
+
background: rgba(0, 125, 181, 0.6) !important;
|
|
84
|
+
}
|
|
85
|
+
.kg-audio-volume-slider::before {
|
|
86
|
+
width: var(--volume-before-width) !important;
|
|
87
|
+
}
|
|
88
|
+
.kg-audio-mute-icon {
|
|
89
|
+
margin: 0 2.5%;
|
|
90
|
+
}
|
|
91
|
+
.kg-audio-player-container input[type="range"] {
|
|
92
|
+
position: relative;
|
|
93
|
+
-webkit-appearance: none;
|
|
94
|
+
width: 48%;
|
|
95
|
+
margin: 0;
|
|
96
|
+
padding: 0;
|
|
97
|
+
height: 19px;
|
|
98
|
+
margin: 30px 2.5% 20px 2.5%;
|
|
99
|
+
float: left;
|
|
100
|
+
outline: none;
|
|
101
|
+
}
|
|
102
|
+
.kg-audio-player-container input[type="range"]::-webkit-slider-runnable-track {
|
|
103
|
+
width: 100%;
|
|
104
|
+
height: 3px;
|
|
105
|
+
cursor: pointer;
|
|
106
|
+
background: linear-gradient(to right, rgba(0, 125, 181, 0.6) var(--buffered-width), rgba(0, 125, 181, 0.2) var(--buffered-width));
|
|
107
|
+
}
|
|
108
|
+
.kg-audio-player-container input[type="range"]::before {
|
|
109
|
+
position: absolute;
|
|
110
|
+
content: "";
|
|
111
|
+
top: 8px;
|
|
112
|
+
left: 0;
|
|
113
|
+
width: var(--seek-before-width);
|
|
114
|
+
height: 3px;
|
|
115
|
+
background-color: #007db5;
|
|
116
|
+
cursor: pointer;
|
|
117
|
+
}
|
|
118
|
+
.kg-audio-player-container input[type="range"]::-webkit-slider-thumb {
|
|
119
|
+
position: relative;
|
|
120
|
+
-webkit-appearance: none;
|
|
121
|
+
box-sizing: content-box;
|
|
122
|
+
border: 1px solid #007db5;
|
|
123
|
+
height: 15px;
|
|
124
|
+
width: 15px;
|
|
125
|
+
border-radius: 50%;
|
|
126
|
+
background-color: #fff;
|
|
127
|
+
cursor: pointer;
|
|
128
|
+
margin: -7px 0 0 0;
|
|
129
|
+
}
|
|
130
|
+
.kg-audio-player-container input[type="range"]:active::-webkit-slider-thumb {
|
|
131
|
+
transform: scale(1.2);
|
|
132
|
+
background: #007db5;
|
|
133
|
+
}
|
|
134
|
+
.kg-audio-player-container input[type="range"]::-moz-range-track {
|
|
135
|
+
width: 100%;
|
|
136
|
+
height: 3px;
|
|
137
|
+
cursor: pointer;
|
|
138
|
+
background: linear-gradient(to right, rgba(0, 125, 181, 0.6) var(--buffered-width), rgba(0, 125, 181, 0.2) var(--buffered-width));
|
|
139
|
+
}
|
|
140
|
+
.kg-audio-player-container input[type="range"]::-moz-range-progress {
|
|
141
|
+
background-color: #007db5;
|
|
142
|
+
}
|
|
143
|
+
.kg-audio-player-container input[type="range"]::-moz-focus-outer {
|
|
144
|
+
border: 0;
|
|
145
|
+
}
|
|
146
|
+
.kg-audio-player-container input[type="range"]::-moz-range-thumb {
|
|
147
|
+
box-sizing: content-box;
|
|
148
|
+
border: 1px solid #007db5;
|
|
149
|
+
height: 15px;
|
|
150
|
+
width: 15px;
|
|
151
|
+
border-radius: 50%;
|
|
152
|
+
background-color: #fff;
|
|
153
|
+
cursor: pointer;
|
|
154
|
+
}
|
|
155
|
+
.kg-audio-player-container input[type="range"]:active::-moz-range-thumb {
|
|
156
|
+
transform: scale(1.2);
|
|
157
|
+
background: #007db5;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.kg-audio-player-container input[type="range"]::-ms-track {
|
|
161
|
+
width: 100%;
|
|
162
|
+
height: 3px;
|
|
163
|
+
cursor: pointer;
|
|
164
|
+
background: transparent;
|
|
165
|
+
border: solid transparent;
|
|
166
|
+
color: transparent;
|
|
167
|
+
}
|
|
168
|
+
.kg-audio-player-container input[type="range"]::-ms-fill-lower {
|
|
169
|
+
background-color: #007db5;
|
|
170
|
+
}
|
|
171
|
+
.kg-audio-player-container input[type="range"]::-ms-fill-upper {
|
|
172
|
+
background: linear-gradient(to right, rgba(0, 125, 181, 0.6) var(--buffered-width), rgba(0, 125, 181, 0.2) var(--buffered-width));
|
|
173
|
+
}
|
|
174
|
+
.kg-audio-player-container input[type="range"]::-ms-thumb {
|
|
175
|
+
box-sizing: content-box;
|
|
176
|
+
border: 1px solid #007db5;
|
|
177
|
+
height: 15px;
|
|
178
|
+
width: 15px;
|
|
179
|
+
border-radius: 50%;
|
|
180
|
+
background-color: #fff;
|
|
181
|
+
cursor: pointer;
|
|
182
|
+
}
|
|
183
|
+
.kg-audio-player-container input[type="range"]:active::-ms-thumb {
|
|
184
|
+
transform: scale(1.2);
|
|
185
|
+
background: #007db5;
|
|
186
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
blockquote.kg-blockquote-alt {
|
|
2
|
+
background: none;
|
|
3
|
+
font-size: 1.6em;
|
|
4
|
+
line-height: 1.7em;
|
|
5
|
+
text-align: center;
|
|
6
|
+
padding: 0.5em 2.5em 0.75em;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
blockquote.kg-blockquote-alt::before {
|
|
10
|
+
display: none;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
@media (max-width: 800px) {
|
|
14
|
+
blockquote.kg-blockquote-alt {
|
|
15
|
+
font-size: 1.4em;
|
|
16
|
+
padding-left: 2em;
|
|
17
|
+
padding-right: 2em;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@media (max-width: 600px) {
|
|
22
|
+
blockquote.kg-blockquote-alt {
|
|
23
|
+
font-size: 1.2em;
|
|
24
|
+
padding-left: 1.75em;
|
|
25
|
+
padding-right: 1.75em;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
align-items: flex-start;
|
|
22
22
|
justify-content: flex-start;
|
|
23
23
|
padding: 20px;
|
|
24
|
+
overflow: hidden;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
.kg-bookmark-title {
|
|
@@ -49,6 +50,7 @@
|
|
|
49
50
|
width: 100%;
|
|
50
51
|
font-size: 1.4rem;
|
|
51
52
|
font-weight: 500;
|
|
53
|
+
white-space: nowrap;
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
.kg-bookmark-metadata > *:not(img) {
|
|
@@ -84,6 +86,11 @@
|
|
|
84
86
|
margin: 0 6px;
|
|
85
87
|
}
|
|
86
88
|
|
|
89
|
+
.kg-bookmark-metadata > span:last-of-type {
|
|
90
|
+
overflow: hidden;
|
|
91
|
+
text-overflow: ellipsis;
|
|
92
|
+
}
|
|
93
|
+
|
|
87
94
|
.kg-bookmark-thumbnail {
|
|
88
95
|
position: relative;
|
|
89
96
|
flex-grow: 1;
|
|
@@ -1,50 +1,58 @@
|
|
|
1
|
-
.kg-card
|
|
1
|
+
.kg-callout-card {
|
|
2
2
|
display: flex;
|
|
3
|
-
|
|
4
|
-
padding: 20px 28px;
|
|
3
|
+
padding: 1.2em 1.6em;
|
|
5
4
|
border-radius: 3px;
|
|
6
5
|
}
|
|
7
6
|
|
|
8
|
-
.kg-card-
|
|
7
|
+
.kg-callout-card-grey {
|
|
9
8
|
background: rgba(124, 139, 154, 0.13);
|
|
10
9
|
}
|
|
11
10
|
|
|
12
|
-
.kg-card-
|
|
11
|
+
.kg-callout-card-white {
|
|
13
12
|
background: transparent;
|
|
14
13
|
box-shadow: inset 0 0 0 1px rgba(124, 139, 154, 0.25);
|
|
15
14
|
}
|
|
16
15
|
|
|
17
|
-
.kg-card-
|
|
16
|
+
.kg-callout-card-blue {
|
|
18
17
|
background: rgba(33, 172, 232, 0.12);
|
|
19
18
|
}
|
|
20
19
|
|
|
21
|
-
.kg-card-
|
|
20
|
+
.kg-callout-card-green {
|
|
22
21
|
background: rgba(52, 183, 67, 0.12);
|
|
23
22
|
}
|
|
24
23
|
|
|
25
|
-
.kg-card-
|
|
24
|
+
.kg-callout-card-yellow {
|
|
26
25
|
background: rgba(240, 165, 15, 0.13);
|
|
27
26
|
}
|
|
28
27
|
|
|
29
|
-
.kg-card-
|
|
28
|
+
.kg-callout-card-red {
|
|
30
29
|
background: rgba(209, 46, 46, 0.11);
|
|
31
30
|
}
|
|
32
31
|
|
|
33
|
-
.kg-card-
|
|
32
|
+
.kg-callout-card-pink {
|
|
34
33
|
background: rgba(225, 71, 174, 0.11);
|
|
35
34
|
}
|
|
36
35
|
|
|
37
|
-
.kg-card-
|
|
36
|
+
.kg-callout-card-purple {
|
|
38
37
|
background: rgba(135, 85, 236, 0.12);
|
|
39
38
|
}
|
|
40
39
|
|
|
41
|
-
.kg-card-
|
|
40
|
+
.kg-callout-card-accent {
|
|
42
41
|
background: var(--ghost-accent-color);
|
|
43
42
|
color: #fff;
|
|
44
43
|
}
|
|
45
44
|
|
|
45
|
+
.kg-callout-card-accent a {
|
|
46
|
+
color: #fff;
|
|
47
|
+
}
|
|
48
|
+
|
|
46
49
|
.kg-callout-emoji {
|
|
47
|
-
padding-right:
|
|
48
|
-
line-height: 1.
|
|
49
|
-
font-size:
|
|
50
|
+
padding-right: .8em;
|
|
51
|
+
line-height: 1.3em;
|
|
52
|
+
font-size: 1.2em;
|
|
50
53
|
}
|
|
54
|
+
|
|
55
|
+
.kg-callout-text {
|
|
56
|
+
font-size: .95em;
|
|
57
|
+
line-height: 1.5em;
|
|
58
|
+
}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
.kg-gallery-card {
|
|
2
|
+
--gap: 1.2rem;
|
|
3
|
+
}
|
|
4
|
+
|
|
1
5
|
.kg-image-card:not(.kg-card-hascaption) + .kg-image-card,
|
|
2
6
|
.kg-image-card:not(.kg-card-hascaption) + .kg-gallery-card,
|
|
3
7
|
.kg-gallery-card:not(.kg-card-hascaption) + .kg-image-card,
|
|
4
8
|
.kg-gallery-card:not(.kg-card-hascaption) + .kg-gallery-card {
|
|
5
|
-
margin-top:
|
|
9
|
+
margin-top: var(--gap);
|
|
6
10
|
}
|
|
7
11
|
|
|
8
12
|
.kg-gallery-container {
|
|
@@ -23,9 +27,15 @@
|
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
.kg-gallery-row:not(:first-of-type) {
|
|
26
|
-
margin:
|
|
30
|
+
margin: var(--gap) 0 0;
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
.kg-gallery-image:not(:first-of-type) {
|
|
30
|
-
margin: 0 0 0
|
|
34
|
+
margin: 0 0 0 var(--gap);
|
|
31
35
|
}
|
|
36
|
+
|
|
37
|
+
@media (max-width: 600px) {
|
|
38
|
+
.kg-gallery-card {
|
|
39
|
+
--gap: 0.6rem;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -1,8 +1,30 @@
|
|
|
1
|
+
.kg-toggle-card+.kg-toggle-card {
|
|
2
|
+
margin-top: 1em;
|
|
3
|
+
}
|
|
4
|
+
|
|
1
5
|
.kg-toggle-card[data-kg-toggle-state="close"] .kg-toggle-content{
|
|
2
|
-
|
|
3
|
-
opacity:
|
|
6
|
+
height: auto;
|
|
7
|
+
opacity: 1;
|
|
8
|
+
transition: opacity 1s ease, top .35s ease;
|
|
9
|
+
top: 0;
|
|
10
|
+
position: relative;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.kg-toggle-content {
|
|
4
14
|
height: 0;
|
|
5
|
-
|
|
15
|
+
overflow: hidden;
|
|
16
|
+
transition: opacity .5s ease, top .35s ease;
|
|
17
|
+
opacity: 0;
|
|
18
|
+
top: -0.5em;
|
|
19
|
+
position: relative;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.kg-toggle-content p:first-of-type {
|
|
23
|
+
margin-top: 0.5em;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.kg-toggle-content p {
|
|
27
|
+
font-size: 0.95em;
|
|
6
28
|
}
|
|
7
29
|
|
|
8
30
|
.kg-toggle-card[data-kg-toggle-state="close"] svg {
|
|
@@ -10,14 +32,13 @@
|
|
|
10
32
|
}
|
|
11
33
|
|
|
12
34
|
.kg-toggle-card {
|
|
13
|
-
|
|
35
|
+
background: transparent;
|
|
36
|
+
box-shadow: inset 0 0 0 1px rgba(124, 139, 154, 0.25);
|
|
14
37
|
border-radius: 4px;
|
|
15
|
-
padding:
|
|
38
|
+
padding: 1.2em;
|
|
16
39
|
}
|
|
17
40
|
|
|
18
41
|
.kg-toggle-heading {
|
|
19
|
-
font-size: 2rem;
|
|
20
|
-
font-weight: 600;
|
|
21
42
|
cursor: pointer;
|
|
22
43
|
display: flex;
|
|
23
44
|
justify-content: space-between;
|
|
@@ -30,18 +51,30 @@
|
|
|
30
51
|
display: flex;
|
|
31
52
|
justify-content: center;
|
|
32
53
|
align-items: center;
|
|
33
|
-
margin-left:
|
|
54
|
+
margin-left: 1em;
|
|
55
|
+
background: none;
|
|
56
|
+
border: 0;
|
|
34
57
|
}
|
|
35
58
|
|
|
36
59
|
.kg-toggle-heading svg {
|
|
37
60
|
width: 14px;
|
|
38
|
-
color: rgba(
|
|
39
|
-
transition:
|
|
40
|
-
transform: rotate(180deg);
|
|
61
|
+
color: rgba(124, 139, 154, 0.5);
|
|
62
|
+
transition: all 0.3s;
|
|
63
|
+
transform: rotate(-180deg);
|
|
41
64
|
}
|
|
42
65
|
|
|
43
|
-
.kg-toggle-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
66
|
+
.kg-toggle-heading path {
|
|
67
|
+
fill: none;
|
|
68
|
+
stroke: currentcolor;
|
|
69
|
+
stroke-linecap: round;
|
|
70
|
+
stroke-linejoin: round;
|
|
71
|
+
stroke-width: 1.5;
|
|
72
|
+
fill-rule: evenodd;
|
|
47
73
|
}
|
|
74
|
+
|
|
75
|
+
.kg-toggle-heading-text {
|
|
76
|
+
margin-top: 0;
|
|
77
|
+
margin-bottom: 0;
|
|
78
|
+
line-height: 1.3em;
|
|
79
|
+
font-size: 1.1em;
|
|
80
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
const handleAudioPlayer = function (audioElementContainer) {
|
|
2
|
+
const audioPlayerContainer = audioElementContainer.querySelector('.kg-audio-player-container');
|
|
3
|
+
const playIconContainer = audioElementContainer.querySelector('.kg-audio-play-icon');
|
|
4
|
+
const seekSlider = audioElementContainer.querySelector('.kg-audio-seek-slider');
|
|
5
|
+
const volumeSlider = audioElementContainer.querySelector('.kg-audio-volume-slider');
|
|
6
|
+
const muteIconContainer = audioElementContainer.querySelector('.kg-audio-mute-icon');
|
|
7
|
+
const playbackRateContainer = audioElementContainer.querySelector('.kg-audio-playback-rate');
|
|
8
|
+
const audio = audioElementContainer.querySelector('audio');
|
|
9
|
+
const durationContainer = audioElementContainer.querySelector('.kg-audio-duration');
|
|
10
|
+
const currentTimeContainer = audioElementContainer.querySelector('.kg-audio-current-time');
|
|
11
|
+
const outputContainer = audioElementContainer.querySelector('.kg-audio-volume-output');
|
|
12
|
+
let playState = 'play';
|
|
13
|
+
let muteState = 'unmute';
|
|
14
|
+
let playbackRate = 1.0;
|
|
15
|
+
let raf = null;
|
|
16
|
+
|
|
17
|
+
audio.src = audioElementContainer.getAttribute('data-kg-audio-src');
|
|
18
|
+
|
|
19
|
+
const whilePlaying = () => {
|
|
20
|
+
seekSlider.value = Math.floor(audio.currentTime);
|
|
21
|
+
currentTimeContainer.textContent = calculateTime(seekSlider.value);
|
|
22
|
+
audioPlayerContainer.style.setProperty('--seek-before-width', `${seekSlider.value / seekSlider.max * 100}%`);
|
|
23
|
+
raf = requestAnimationFrame(whilePlaying);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const showRangeProgress = (rangeInput) => {
|
|
27
|
+
if (rangeInput === seekSlider) {
|
|
28
|
+
audioPlayerContainer.style.setProperty('--seek-before-width', rangeInput.value / rangeInput.max * 100 + '%');
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
audioPlayerContainer.style.setProperty('--volume-before-width', rangeInput.value / rangeInput.max * 100 + '%');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const calculateTime = (secs) => {
|
|
36
|
+
const minutes = Math.floor(secs / 60);
|
|
37
|
+
const seconds = Math.floor(secs % 60);
|
|
38
|
+
const returnedSeconds = seconds < 10 ? `0${seconds}` : `${seconds}`;
|
|
39
|
+
return `${minutes}:${returnedSeconds}`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const displayDuration = () => {
|
|
43
|
+
durationContainer.textContent = calculateTime(audio.duration);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const setSliderMax = () => {
|
|
47
|
+
seekSlider.max = Math.floor(audio.duration);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const displayBufferedAmount = () => {
|
|
51
|
+
if (audio.buffered.length > 0) {
|
|
52
|
+
const bufferedAmount = Math.floor(audio.buffered.end(audio.buffered.length - 1));
|
|
53
|
+
audioPlayerContainer.style.setProperty('--buffered-width', `${(bufferedAmount / seekSlider.max) * 100}%`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (audio.readyState > 0) {
|
|
58
|
+
displayDuration();
|
|
59
|
+
setSliderMax();
|
|
60
|
+
displayBufferedAmount();
|
|
61
|
+
} else {
|
|
62
|
+
audio.addEventListener('loadedmetadata', () => {
|
|
63
|
+
displayDuration();
|
|
64
|
+
setSliderMax();
|
|
65
|
+
displayBufferedAmount();
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
playIconContainer.addEventListener('click', () => {
|
|
70
|
+
if (playState === 'play') {
|
|
71
|
+
audio.play();
|
|
72
|
+
requestAnimationFrame(whilePlaying);
|
|
73
|
+
playState = 'pause';
|
|
74
|
+
playIconContainer.textContent = '||';
|
|
75
|
+
} else {
|
|
76
|
+
audio.pause();
|
|
77
|
+
cancelAnimationFrame(raf);
|
|
78
|
+
playState = 'play';
|
|
79
|
+
playIconContainer.textContent = '>';
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
muteIconContainer.addEventListener('click', () => {
|
|
84
|
+
if (muteState === 'unmute') {
|
|
85
|
+
audio.muted = true;
|
|
86
|
+
muteState = 'mute';
|
|
87
|
+
muteIconContainer.textContent = 'UM';
|
|
88
|
+
} else {
|
|
89
|
+
audio.muted = false;
|
|
90
|
+
muteState = 'unmute';
|
|
91
|
+
muteIconContainer.textContent = 'M';
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
playbackRateContainer.addEventListener('click', () => {
|
|
96
|
+
if (playbackRate === 1.0) {
|
|
97
|
+
audio.playbackRate = 2;
|
|
98
|
+
playbackRate = 2;
|
|
99
|
+
playbackRateContainer.textContent = '2x';
|
|
100
|
+
} else {
|
|
101
|
+
audio.playbackRate = 1.0;
|
|
102
|
+
playbackRate = 1.0;
|
|
103
|
+
playbackRateContainer.textContent = '1x';
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
audio.addEventListener('progress', displayBufferedAmount);
|
|
108
|
+
|
|
109
|
+
seekSlider.addEventListener('input', (e) => {
|
|
110
|
+
showRangeProgress(e.target);
|
|
111
|
+
currentTimeContainer.textContent = calculateTime(seekSlider.value);
|
|
112
|
+
if (!audio.paused) {
|
|
113
|
+
cancelAnimationFrame(raf);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
seekSlider.addEventListener('change', () => {
|
|
118
|
+
audio.currentTime = seekSlider.value;
|
|
119
|
+
if (!audio.paused) {
|
|
120
|
+
requestAnimationFrame(whilePlaying);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
volumeSlider.addEventListener('input', (e) => {
|
|
125
|
+
const value = e.target.value;
|
|
126
|
+
showRangeProgress(e.target);
|
|
127
|
+
outputContainer.textContent = value;
|
|
128
|
+
audio.volume = value / 100;
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const audioCardElements = document.querySelectorAll('.kg-audio-card');
|
|
133
|
+
|
|
134
|
+
for (let i = 0; i < audioCardElements.length; i++) {
|
|
135
|
+
handleAudioPlayer(audioCardElements[i]);
|
|
136
|
+
}
|
|
137
|
+
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
const hbs = require('express-hbs');
|
|
2
|
+
const _ = require('lodash');
|
|
3
|
+
const tpl = require('@tryghost/tpl');
|
|
4
|
+
const sentry = require('../../../shared/sentry');
|
|
5
|
+
|
|
6
|
+
const config = require('../../../shared/config');
|
|
7
|
+
const helpers = require('../../services/routing/helpers');
|
|
8
|
+
|
|
9
|
+
// @TODO: make this properly shared code
|
|
10
|
+
const shared = require('../../../server/web/shared/middleware/error-handler');
|
|
11
|
+
|
|
12
|
+
const messages = {
|
|
13
|
+
oopsErrorTemplateHasError: 'Oops, seems there is an error in the error template.',
|
|
14
|
+
encounteredError: 'Encountered the error: ',
|
|
15
|
+
whilstTryingToRender: 'whilst trying to render an error page for the error: '
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const escapeExpression = hbs.Utils.escapeExpression;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* This is a bare minimum setup, which allows us to render the error page
|
|
22
|
+
* It uses the {{asset}} helper, and nothing more
|
|
23
|
+
*/
|
|
24
|
+
const createHbsEngine = () => {
|
|
25
|
+
const engine = hbs.create();
|
|
26
|
+
engine.registerHelper('asset', require('../../helpers/asset'));
|
|
27
|
+
|
|
28
|
+
return engine.express4();
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const errorFallbackMessage = err => `<h1>${tpl(messages.oopsErrorTemplateHasError)}</h1>
|
|
32
|
+
<p>${tpl(messages.encounteredError)}</p>
|
|
33
|
+
<pre>${escapeExpression(err.message || err)}</pre>
|
|
34
|
+
<br ><p>${tpl(messages.whilstTryingToRender)}</p>
|
|
35
|
+
${err.statusCode} <pre>${escapeExpression(err.message || err)}</pre>`;
|
|
36
|
+
|
|
37
|
+
const themeErrorRenderer = (err, req, res, next) => {
|
|
38
|
+
// If the error code is explicitly set to STATIC_FILE_NOT_FOUND,
|
|
39
|
+
// Skip trying to render an HTML error, and move on to the basic error renderer
|
|
40
|
+
// We do this because customised 404 templates could reference the image that's missing
|
|
41
|
+
// A better long term solution might be to do this based on extension
|
|
42
|
+
if (err.code === 'STATIC_FILE_NOT_FOUND') {
|
|
43
|
+
return next(err);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Renderer begin
|
|
47
|
+
// Format Data
|
|
48
|
+
const data = {
|
|
49
|
+
message: err.message,
|
|
50
|
+
// @deprecated Remove in Ghost 5.0
|
|
51
|
+
code: err.statusCode,
|
|
52
|
+
statusCode: err.statusCode,
|
|
53
|
+
errorDetails: err.errorDetails || []
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// Template
|
|
57
|
+
// @TODO: very dirty !!!!!!
|
|
58
|
+
helpers.templates.setTemplate(req, res);
|
|
59
|
+
|
|
60
|
+
// It can be that something went wrong with the theme or otherwise loading handlebars
|
|
61
|
+
// This ensures that no matter what res.render will work here
|
|
62
|
+
// @TODO: split the error handler for assets, admin & theme to refactor this away
|
|
63
|
+
if (_.isEmpty(req.app.engines)) {
|
|
64
|
+
res._template = 'error';
|
|
65
|
+
req.app.engine('hbs', createHbsEngine());
|
|
66
|
+
req.app.set('view engine', 'hbs');
|
|
67
|
+
req.app.set('views', config.get('paths').defaultViews);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// @TODO use renderer here?!
|
|
71
|
+
// Render Call - featuring an error handler for what happens if rendering fails
|
|
72
|
+
res.render(res._template, data, (_err, html) => {
|
|
73
|
+
if (!_err) {
|
|
74
|
+
return res.send(html);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// re-attach new error e.g. error template has syntax error or misusage
|
|
78
|
+
req.err = _err;
|
|
79
|
+
|
|
80
|
+
// And then try to explain things to the user...
|
|
81
|
+
// Cheat and output the error using handlebars escapeExpression
|
|
82
|
+
return res.status(500).send(errorFallbackMessage(_err));
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
module.exports.handleThemeResponse = [
|
|
87
|
+
// Make sure the error can be served
|
|
88
|
+
shared.prepareError,
|
|
89
|
+
// Handle the error in Sentry
|
|
90
|
+
sentry.errorHandler,
|
|
91
|
+
// Render the error using theme template
|
|
92
|
+
themeErrorRenderer
|
|
93
|
+
];
|