@anthusai/papyrus 1.0.0-next.4 → 1.0.0-next.41
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/amplify/auth/redirect-urls.js +54 -0
- package/amplify/auth/redirect-urls.ts +66 -0
- package/amplify/auth/resource.js +20 -5
- package/amplify/auth/resource.ts +27 -5
- package/amplify/data/resource.js +28 -70
- package/amplify/data/resource.ts +29 -70
- package/amplify/data/schema.js +33 -58
- package/amplify/data/schema.ts +34 -58
- package/amplify/functions/category-action/handler.ts +5 -3
- package/amplify/functions/console-chat-responder/py/execute_tactus_runner.py +0 -10
- package/amplify/functions/console-chat-responder/resource.js +0 -7
- package/amplify/functions/console-chat-responder/resource.ts +0 -8
- package/amplify/functions/console-chat-responder/src/main.rs +0 -9
- package/amplify/functions/content-actions/handler.py +45 -3
- package/amplify/functions/shared/reference-curation-metadata.ts +29 -0
- package/amplify/inbound-email/ses-intake.js +86 -0
- package/amplify/inbound-email/ses-intake.ts +110 -0
- package/amplify/rebuild-trigger-settings.js +22 -0
- package/amplify/rebuild-trigger-settings.ts +42 -0
- package/amplify/resolver-waves.js +26 -0
- package/amplify/resolver-waves.ts +34 -0
- package/amplify/site-backend-config.ts +36 -1
- package/amplify/site-backend-names.js +103 -0
- package/amplify/site-backend-names.ts +166 -0
- package/amplify/site-backend.js +93 -170
- package/amplify/site-backend.ts +126 -196
- package/amplify/storage/resource.js +3 -0
- package/amplify/storage/resource.ts +3 -0
- package/amplify/storage-backups/construct.js +31 -0
- package/amplify/storage-backups/construct.ts +47 -0
- package/app/%5F_preview/[[...path]]/route.ts +8 -0
- package/app/[year]/[month]/[day]/[articleSlug]/page.tsx +2 -0
- package/app/[year]/[month]/[day]/edition-route-page.tsx +2 -0
- package/app/api/media/[...path]/route.ts +5 -16
- package/app/api/revalidate/route.ts +8 -7
- package/app/articles/[slug]/page.tsx +6 -4
- package/app/blog-rhythm.css +278 -0
- package/app/globals.css +21 -0
- package/app/layout.tsx +16 -0
- package/app/newsroom/[section]/[...selection]/page.tsx +6 -5
- package/app/newsroom/[section]/page.tsx +4 -3
- package/app/newsroom/articles/[id]/page.tsx +15 -0
- package/app/newsroom/articles/page.tsx +13 -0
- package/app/newsroom/layout.tsx +4 -9
- package/app/page.tsx +18 -5
- package/app/robots.ts +2 -5
- package/bin/papyrus-app.mjs +12 -2
- package/bin/papyrus-infra.mjs +29 -3
- package/components/amplify-client-provider.tsx +4 -22
- package/components/archive-shell.tsx +2 -22
- package/components/article-video.tsx +247 -3
- package/components/blog-page-background.tsx +23 -6
- package/components/markus-ir-preview.tsx +300 -0
- package/components/news-desk-taxonomy-client.ts +51 -0
- package/components/newspaper.tsx +6 -2
- package/components/newsroom-access-gate.tsx +67 -0
- package/components/newsroom-article-editor.tsx +741 -0
- package/components/newsroom-articles-view.tsx +129 -0
- package/components/newsroom-client-shell.tsx +12 -0
- package/components/newsroom-ops-overview.tsx +28 -11
- package/components/newsroom-ops-shell.tsx +3 -1
- package/components/newsroom-references-view.tsx +83 -8
- package/components/papyrus-console-shell.tsx +4 -2
- package/components/pictogram-figure.tsx +9 -2
- package/components/presentation-header.tsx +135 -0
- package/components/presentation-rhythm-hrule.tsx +17 -0
- package/components/reference-cyclotron-status.tsx +109 -0
- package/components/reference-relevance-review.tsx +75 -0
- package/components/settings-page.tsx +2 -1
- package/components/topic-steering-workspace.tsx +54 -64
- package/components/use-blog-header-obstacles.ts +81 -0
- package/components/use-brand-fonts-ready.ts +28 -0
- package/components/use-rhythm-overlay.ts +29 -0
- package/infra/amplify-app-shell.js +228 -50
- package/infra/amplify-app-shell.ts +256 -53
- package/infra/build-specs.js +15 -5
- package/infra/build-specs.ts +18 -7
- package/infra/github-oidc-provider.js +24 -0
- package/infra/github-oidc-provider.ts +30 -0
- package/infra/index.js +1 -0
- package/infra/site-config.js +236 -11
- package/infra/site-config.ts +276 -15
- package/lib/amplify-outputs-path.ts +5 -1
- package/lib/blog-feature-solver.ts +459 -0
- package/lib/blog-rhythm.ts +134 -0
- package/lib/brand-fonts-watch.ts +43 -0
- package/lib/brand-fonts.ts +112 -0
- package/lib/cached-content-repository.ts +12 -0
- package/lib/category-repository.ts +42 -93
- package/lib/content-actions-demo.ts +190 -0
- package/lib/content-repository.ts +3 -0
- package/lib/content-source-context.ts +12 -2
- package/lib/content-types.ts +4 -0
- package/lib/edition-routes.ts +31 -29
- package/lib/graphql-content-repository.ts +61 -9
- package/lib/media-route-response.ts +45 -0
- package/lib/newspaper-layout.ts +3 -2
- package/lib/newsroom-articles.ts +325 -0
- package/lib/newsroom-base-path.ts +12 -3
- package/lib/newsroom-category-drilldown.ts +3 -2
- package/lib/newsroom-demo-articles.ts +90 -0
- package/lib/newsroom-forum-routes.ts +6 -4
- package/lib/newsroom-index-filters.ts +14 -10
- package/lib/newsroom-media-backend.ts +142 -0
- package/lib/newsroom-media.ts +182 -0
- package/lib/newsroom-nav.ts +3 -0
- package/lib/oauth-redirect-priority.ts +40 -0
- package/lib/papyrus-web-locations.ts +7 -6
- package/lib/presentation-footer.ts +3 -2
- package/lib/pretext-layout.ts +12 -3
- package/lib/reader-base-path.ts +24 -0
- package/lib/reader-static-params.ts +13 -0
- package/lib/reference-policy.ts +5 -0
- package/lib/relevance-decisions.ts +103 -0
- package/lib/relevance-status.ts +63 -0
- package/lib/renderer.ts +7 -0
- package/lib/revalidate-secret.ts +59 -0
- package/lib/robots-policy.ts +14 -0
- package/lib/root-route-redirect.ts +16 -0
- package/lib/semantic-graph.ts +7 -0
- package/lib/site-brand.ts +51 -0
- package/lib/staging-gated-path.ts +23 -0
- package/lib/staging-preview-object.ts +114 -0
- package/lib/video-mode.ts +42 -0
- package/lib/video-script.ts +77 -0
- package/middleware.ts +23 -18
- package/package.json +45 -1
- package/renderers/pretext/article-page.tsx +39 -3
- package/renderers/pretext/presentation-shared.tsx +113 -0
- package/renderers/pretext/presentation-shell.tsx +15 -102
- package/renderers/pretext/rhythm-article-page.tsx +165 -0
- package/renderers/pretext/rhythm-blog-presentation.tsx +279 -0
- package/renderers/pretext/rhythm-shell-style.ts +35 -0
- package/routes.manifest.json +45 -2
- package/scripts/videoml/build-browser-bundle.mjs +22 -0
- package/scripts/videoml/build-preview-bundle.mjs +50 -0
- package/scripts/videoml/bundle-common.mjs +129 -0
- package/scripts/videoml/preview/preview-entry.tsx +381 -0
- package/scripts/videoml/preview/preview-stage-fit.ts +28 -0
- package/scripts/videoml/preview/preview-timing.ts +42 -0
- package/scripts/videoml/preview.html +77 -0
- package/scripts/videoml/standard-entry.tsx +46 -0
- package/src/sync.mjs +30 -6
- package/src/with-papyrus.mjs +19 -2
- package/amplify/functions/graphql-jwt-authorizer/handler.ts +0 -193
- package/amplify/functions/graphql-jwt-authorizer/resource.js +0 -14
- package/amplify/functions/graphql-jwt-authorizer/resource.ts +0 -15
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { notFound } from "next/navigation";
|
|
2
2
|
import { getSiteRenderer } from "../../../lib/site-renderer";
|
|
3
|
-
import { getCachedArticle } from "../../../lib/cached-content-repository";
|
|
4
|
-
import { generateArticleStaticParams } from "../../../lib/reader-static-params";
|
|
3
|
+
import { getCachedArticle, getCachedVideoScript } from "../../../lib/cached-content-repository";
|
|
4
|
+
import { generateArticleStaticParams, siteServesNextReaderRoutes } from "../../../lib/reader-static-params";
|
|
5
5
|
import { SITE_BRAND } from "../../../lib/site-brand";
|
|
6
6
|
|
|
7
7
|
// Keep in sync with READER_REVALIDATE_SECONDS in lib/reader-route-config.ts
|
|
@@ -16,6 +16,7 @@ type ArticlePageProps = {
|
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
export async function generateMetadata({ params }: ArticlePageProps) {
|
|
19
|
+
if (!siteServesNextReaderRoutes()) return {};
|
|
19
20
|
const { slug } = await params;
|
|
20
21
|
const article = await getCachedArticle(slug);
|
|
21
22
|
if (!article) return {};
|
|
@@ -26,10 +27,11 @@ export async function generateMetadata({ params }: ArticlePageProps) {
|
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
export default async function ArticlePage({ params }: ArticlePageProps) {
|
|
30
|
+
if (!siteServesNextReaderRoutes()) notFound();
|
|
29
31
|
const { slug } = await params;
|
|
30
|
-
const article = await getCachedArticle(slug);
|
|
32
|
+
const [article, videoScript] = await Promise.all([getCachedArticle(slug), getCachedVideoScript(slug)]);
|
|
31
33
|
if (!article) notFound();
|
|
32
34
|
|
|
33
35
|
const siteRenderer = getSiteRenderer();
|
|
34
|
-
return <siteRenderer.renderArticle article={article} backHref="/" />;
|
|
36
|
+
return <siteRenderer.renderArticle article={article} videoScript={videoScript} backHref="/" />;
|
|
35
37
|
}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Structural CSS for the rhythm blog layout (blogLayout: "rhythm").
|
|
3
|
+
Every rule is scoped to .blog-rhythm-shell, which only the rhythm layout
|
|
4
|
+
renders, so classic layouts are unaffected. The shell sets --blog-rhythm,
|
|
5
|
+
--blog-row-height, --blog-paint-buffer and --blog-paint-height inline.
|
|
6
|
+
Typography, colors and the header look belong to the publication's theme.css.
|
|
7
|
+
Optional tokens a publication may set:
|
|
8
|
+
--blog-hrule-foreground, --blog-section-rule, --blog-section-band-height,
|
|
9
|
+
--blog-page-padding-x, --blog-secondary-pair-min-width.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
.blog-rhythm-shell {
|
|
13
|
+
--blog-hrule-foreground: var(--border);
|
|
14
|
+
--blog-section-rule: var(--border);
|
|
15
|
+
--blog-section-band-height: calc(var(--blog-row-height) * 2);
|
|
16
|
+
--blog-page-padding-x: calc(var(--blog-rhythm) * 3);
|
|
17
|
+
--paper-rhythm: var(--blog-row-height);
|
|
18
|
+
|
|
19
|
+
isolation: isolate;
|
|
20
|
+
position: relative;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.blog-rhythm-shell.presentation-page--blog {
|
|
24
|
+
padding: calc(var(--blog-row-height) * 4) var(--blog-page-padding-x) 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.blog-rhythm-shell > :not(.blog-page-background) {
|
|
28
|
+
position: relative;
|
|
29
|
+
z-index: 1;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.blog-rhythm-shell[data-rhythm-overlay="true"]::before {
|
|
33
|
+
background-image:
|
|
34
|
+
repeating-linear-gradient(
|
|
35
|
+
to bottom,
|
|
36
|
+
rgb(var(--rhythm-overlay-rule-rgb) / var(--rhythm-overlay-rule-alpha)) 0,
|
|
37
|
+
rgb(var(--rhythm-overlay-rule-rgb) / var(--rhythm-overlay-rule-alpha)) 1px,
|
|
38
|
+
transparent 1px,
|
|
39
|
+
transparent var(--blog-row-height)
|
|
40
|
+
),
|
|
41
|
+
repeating-linear-gradient(
|
|
42
|
+
to bottom,
|
|
43
|
+
rgb(var(--rhythm-overlay-blue-rgb) / var(--rhythm-overlay-blue-alpha)) 0,
|
|
44
|
+
rgb(var(--rhythm-overlay-blue-rgb) / var(--rhythm-overlay-blue-alpha)) var(--blog-row-height),
|
|
45
|
+
rgb(var(--rhythm-overlay-yellow-rgb) / var(--rhythm-overlay-yellow-alpha)) var(--blog-row-height),
|
|
46
|
+
rgb(var(--rhythm-overlay-yellow-rgb) / var(--rhythm-overlay-yellow-alpha)) calc(var(--blog-row-height) * 2)
|
|
47
|
+
);
|
|
48
|
+
content: "";
|
|
49
|
+
inset: 0;
|
|
50
|
+
pointer-events: none;
|
|
51
|
+
position: absolute;
|
|
52
|
+
z-index: 900;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.blog-rhythm-shell .presentation-header {
|
|
56
|
+
max-width: 100%;
|
|
57
|
+
min-width: 0;
|
|
58
|
+
width: 100%;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.blog-rhythm-shell .presentation-section-header,
|
|
62
|
+
.blog-rhythm-shell .presentation-item,
|
|
63
|
+
.blog-rhythm-shell .presentation-item__copy {
|
|
64
|
+
max-width: 100%;
|
|
65
|
+
min-width: 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.blog-rhythm-shell .presentation-section-header {
|
|
69
|
+
align-items: stretch;
|
|
70
|
+
border-bottom: 0;
|
|
71
|
+
border-top: 0;
|
|
72
|
+
display: flex;
|
|
73
|
+
flex-direction: column;
|
|
74
|
+
gap: var(--blog-row-height);
|
|
75
|
+
margin: 0;
|
|
76
|
+
min-height: 0;
|
|
77
|
+
padding: calc(var(--blog-row-height) * 4) 0 calc(var(--blog-row-height) * 2);
|
|
78
|
+
width: 100%;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.blog-rhythm-shell .presentation-section-header__band {
|
|
82
|
+
align-items: center;
|
|
83
|
+
display: grid;
|
|
84
|
+
gap: 0 var(--blog-rhythm);
|
|
85
|
+
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
|
|
86
|
+
grid-template-rows: var(--blog-section-band-height);
|
|
87
|
+
width: 100%;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.blog-rhythm-shell .presentation-section-header__band::before,
|
|
91
|
+
.blog-rhythm-shell .presentation-section-header__band::after {
|
|
92
|
+
background: var(--blog-section-rule);
|
|
93
|
+
content: "";
|
|
94
|
+
grid-row: 1;
|
|
95
|
+
height: var(--blog-section-band-height);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.blog-rhythm-shell .presentation-section-header__band::before {
|
|
99
|
+
grid-column: 1;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.blog-rhythm-shell .presentation-section-header__band::after {
|
|
103
|
+
grid-column: 3;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.blog-rhythm-shell .presentation-section-header__band p {
|
|
107
|
+
grid-column: 2;
|
|
108
|
+
grid-row: 1;
|
|
109
|
+
height: var(--blog-section-band-height);
|
|
110
|
+
justify-self: center;
|
|
111
|
+
line-height: var(--blog-section-band-height);
|
|
112
|
+
margin: 0;
|
|
113
|
+
padding: 0 var(--blog-rhythm);
|
|
114
|
+
width: max-content;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.blog-rhythm-shell .presentation-item {
|
|
118
|
+
border-bottom: 0;
|
|
119
|
+
gap: var(--blog-row-height) calc(var(--blog-rhythm) * 4);
|
|
120
|
+
padding-bottom: 0;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.blog-rhythm-shell .presentation-item--blog {
|
|
124
|
+
grid-template-columns: minmax(0, 1fr);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.blog-rhythm-shell .presentation-rhythm-hrule {
|
|
128
|
+
display: grid;
|
|
129
|
+
grid-column: 1 / -1;
|
|
130
|
+
grid-template-rows: repeat(5, var(--blog-row-height));
|
|
131
|
+
height: calc(var(--blog-row-height) * 5);
|
|
132
|
+
width: 100%;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.blog-rhythm-shell .presentation-rhythm-hrule__line {
|
|
136
|
+
background: var(--blog-hrule-foreground);
|
|
137
|
+
grid-row: 3;
|
|
138
|
+
height: var(--blog-row-height);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
@media (min-width: 1100px) {
|
|
142
|
+
.blog-rhythm-shell .blog-section:has(> .presentation-item[data-item-index="2"]) {
|
|
143
|
+
column-gap: calc(var(--blog-row-height) * 2);
|
|
144
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.blog-rhythm-shell .blog-section:has(> .presentation-item[data-item-index="2"]) > .presentation-section-header,
|
|
148
|
+
.blog-rhythm-shell .blog-section:has(> .presentation-item[data-item-index="2"]) > .presentation-item[data-item-index="0"] {
|
|
149
|
+
grid-column: 1 / -1;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.blog-rhythm-shell .blog-section:has(> .presentation-item[data-item-index="2"]) > .presentation-rhythm-hrule[data-hide-in-secondary-pair="true"] {
|
|
153
|
+
display: none;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.blog-rhythm-shell .presentation-item[data-feature-layout][data-has-image="true"] {
|
|
158
|
+
display: flex;
|
|
159
|
+
flex-direction: column;
|
|
160
|
+
gap: 0;
|
|
161
|
+
grid-template-columns: minmax(0, 1fr);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.blog-rhythm-shell .presentation-item[data-feature-layout] .presentation-item__text-frame {
|
|
165
|
+
height: var(--feature-text-frame-height);
|
|
166
|
+
max-width: none;
|
|
167
|
+
overflow: hidden;
|
|
168
|
+
position: relative;
|
|
169
|
+
width: 100%;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.blog-rhythm-shell .presentation-item[data-feature-layout] .presentation-item__media {
|
|
173
|
+
height: var(--feature-media-height);
|
|
174
|
+
width: var(--feature-image-width);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.blog-rhythm-shell .presentation-item[data-feature-layout] .pictogram-figure__frame {
|
|
178
|
+
aspect-ratio: auto;
|
|
179
|
+
height: var(--feature-image-height);
|
|
180
|
+
width: var(--feature-image-width);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.blog-rhythm-shell .presentation-item--blog[data-feature-layout][data-has-image="true"] .presentation-item__copy {
|
|
184
|
+
display: contents;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.blog-rhythm-shell .presentation-item--blog[data-feature-layout][data-has-image="true"] .presentation-item__header {
|
|
188
|
+
width: 100%;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.blog-rhythm-shell .presentation-item--blog[data-feature-layout][data-has-image="true"] .presentation-item__body {
|
|
192
|
+
min-width: 0;
|
|
193
|
+
position: relative;
|
|
194
|
+
width: 100%;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.blog-rhythm-shell .presentation-item--blog[data-feature-layout][data-has-image="true"] .presentation-item__body .presentation-item__text-frame {
|
|
198
|
+
margin-top: 0;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.blog-rhythm-shell .presentation-item--blog[data-feature-layout][data-has-image="true"] .presentation-item__media {
|
|
202
|
+
margin: 0;
|
|
203
|
+
position: absolute;
|
|
204
|
+
right: 0;
|
|
205
|
+
top: 0;
|
|
206
|
+
z-index: 1;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.blog-rhythm-shell .presentation-item__image img {
|
|
210
|
+
height: 100%;
|
|
211
|
+
object-fit: contain;
|
|
212
|
+
width: 100%;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.blog-rhythm-shell .presentation-item__video {
|
|
216
|
+
grid-column: 1 / -1;
|
|
217
|
+
margin: var(--blog-row-height) 0 0;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.blog-rhythm-shell .article-page__hero-video {
|
|
221
|
+
margin: 0 0 calc(var(--blog-rhythm) * 5);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.blog-rhythm-shell .article-page__hero-video .article-video,
|
|
225
|
+
.blog-rhythm-shell .presentation-item__video-figure {
|
|
226
|
+
container-type: inline-size;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.blog-rhythm-shell .presentation-item__video-figure .article-video__media,
|
|
230
|
+
.blog-rhythm-shell .article-page__hero-video .article-video__media {
|
|
231
|
+
height: round(up, calc(100cqw * 9 / 16), var(--blog-row-height));
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.blog-rhythm-shell .article-float-grid[data-feature-layout][data-has-image="true"] {
|
|
235
|
+
display: grid;
|
|
236
|
+
gap: var(--feature-layout-gap);
|
|
237
|
+
grid-template-columns: minmax(0, 1fr) var(--feature-image-width);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.blog-rhythm-shell .article-float-grid[data-feature-layout] .article-page__hero-video,
|
|
241
|
+
.blog-rhythm-shell .article-float-grid[data-feature-layout] .article-float-grid__header {
|
|
242
|
+
grid-column: 1 / -1;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.blog-rhythm-shell .article-float-grid[data-feature-layout] .article-float-grid__body {
|
|
246
|
+
align-self: start;
|
|
247
|
+
grid-column: 1;
|
|
248
|
+
max-width: var(--feature-copy-width);
|
|
249
|
+
min-width: 0;
|
|
250
|
+
width: var(--feature-copy-width);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.blog-rhythm-shell .article-float-grid[data-feature-layout] .article-float-grid__media,
|
|
254
|
+
.blog-rhythm-shell .article-float-grid[data-feature-layout] .pictogram-figure__frame {
|
|
255
|
+
height: var(--feature-image-height);
|
|
256
|
+
width: var(--feature-image-width);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.blog-rhythm-shell .article-float-grid[data-feature-layout] .pictogram-figure__frame {
|
|
260
|
+
aspect-ratio: auto;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.blog-rhythm-shell .article-float-grid[data-feature-layout] .article-float-grid__media {
|
|
264
|
+
align-self: start;
|
|
265
|
+
grid-column: 2;
|
|
266
|
+
margin: 0;
|
|
267
|
+
position: relative;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.blog-rhythm-shell .article-float-grid .presentation-item__image {
|
|
271
|
+
margin: 0;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
@media (max-width: 900px) {
|
|
275
|
+
.blog-rhythm-shell .presentation-item--blog {
|
|
276
|
+
grid-template-columns: 1fr;
|
|
277
|
+
}
|
|
278
|
+
}
|
package/app/globals.css
CHANGED
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
--color-surface-foreground: var(--surface-foreground);
|
|
46
46
|
--color-foreground-strong: var(--foreground-strong);
|
|
47
47
|
--color-foreground-muted: var(--foreground-muted);
|
|
48
|
+
--color-foreground-subtle: var(--foreground-subtle);
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
:root {
|
|
@@ -71,6 +72,7 @@
|
|
|
71
72
|
--surface-foreground: var(--card-foreground);
|
|
72
73
|
--foreground-strong: var(--slate-12);
|
|
73
74
|
--foreground-muted: var(--slate-10);
|
|
75
|
+
--foreground-subtle: var(--slate-9);
|
|
74
76
|
--border: var(--slate-6);
|
|
75
77
|
--input: var(--slate-6);
|
|
76
78
|
--ring: var(--slate-8);
|
|
@@ -2282,6 +2284,25 @@ img {
|
|
|
2282
2284
|
width: 100%;
|
|
2283
2285
|
}
|
|
2284
2286
|
|
|
2287
|
+
.article-video__preview-frame {
|
|
2288
|
+
aspect-ratio: 16 / 9;
|
|
2289
|
+
background: #000;
|
|
2290
|
+
border: 0;
|
|
2291
|
+
display: block;
|
|
2292
|
+
width: 100%;
|
|
2293
|
+
}
|
|
2294
|
+
|
|
2295
|
+
.article-video__preview-controls {
|
|
2296
|
+
align-items: center;
|
|
2297
|
+
display: flex;
|
|
2298
|
+
gap: 0.75rem;
|
|
2299
|
+
margin-top: 0.5rem;
|
|
2300
|
+
}
|
|
2301
|
+
|
|
2302
|
+
.article-video__preview-controls input[type="range"] {
|
|
2303
|
+
flex: 1;
|
|
2304
|
+
}
|
|
2305
|
+
|
|
2285
2306
|
.article-video__credit {
|
|
2286
2307
|
color: rgb(var(--ink-solid-rgb) / 0.62);
|
|
2287
2308
|
font-size: 0.82rem;
|
package/app/layout.tsx
CHANGED
|
@@ -4,12 +4,14 @@ import Script from "next/script";
|
|
|
4
4
|
import { AmplifyClientProvider } from "../components/amplify-client-provider";
|
|
5
5
|
import { PapyrusConsoleShell } from "../components/papyrus-console-shell";
|
|
6
6
|
import { TooltipProvider } from "../components/ui/tooltip";
|
|
7
|
+
import { resolveBrandFontAssets } from "../lib/brand-fonts";
|
|
7
8
|
import { getPresentationChoices, getSiteBrand } from "../lib/site-brand";
|
|
8
9
|
import { getSiteStack } from "../lib/site-stack";
|
|
9
10
|
import { isIndexable, showStagingBanner } from "../lib/site-env";
|
|
10
11
|
import { StagingBanner } from "../components/staging-banner";
|
|
11
12
|
import "./tailwind.css";
|
|
12
13
|
import "./globals.css";
|
|
14
|
+
import "./blog-rhythm.css";
|
|
13
15
|
import "papyrus-site-theme";
|
|
14
16
|
|
|
15
17
|
const playfairDisplay = Playfair_Display({
|
|
@@ -43,6 +45,7 @@ export default async function RootLayout({ children }: Readonly<{ children: Reac
|
|
|
43
45
|
const siteBrand = getSiteBrand();
|
|
44
46
|
const presentationChoices = getPresentationChoices(siteBrand);
|
|
45
47
|
const siteStack = getSiteStack(siteBrand);
|
|
48
|
+
const brandFonts = resolveBrandFontAssets(siteBrand.fonts);
|
|
46
49
|
|
|
47
50
|
return (
|
|
48
51
|
<html
|
|
@@ -56,8 +59,21 @@ export default async function RootLayout({ children }: Readonly<{ children: Reac
|
|
|
56
59
|
data-default-presentation={siteBrand.defaultPresentation}
|
|
57
60
|
data-presentation-choices={presentationChoices.join(",")}
|
|
58
61
|
{...(siteBrand.forcedPresentation ? { "data-forced-presentation": siteBrand.forcedPresentation } : {})}
|
|
62
|
+
{...(siteBrand.blogLayout === "rhythm" ? { "data-blog-layout": "rhythm" } : {})}
|
|
63
|
+
{...(brandFonts.isEmpty ? {} : { style: brandFonts.rootStyle as React.CSSProperties })}
|
|
59
64
|
suppressHydrationWarning
|
|
60
65
|
>
|
|
66
|
+
{brandFonts.isEmpty ? null : (
|
|
67
|
+
<head>
|
|
68
|
+
{brandFonts.preconnectOrigins.map((origin) => (
|
|
69
|
+
<link crossOrigin="anonymous" href={origin} key={origin} rel="preconnect" />
|
|
70
|
+
))}
|
|
71
|
+
{brandFonts.stylesheetHrefs.map((href) => (
|
|
72
|
+
<link href={href} key={href} rel="stylesheet" />
|
|
73
|
+
))}
|
|
74
|
+
{brandFonts.fontFaceCss ? <style data-brand-fonts="true">{brandFonts.fontFaceCss}</style> : null}
|
|
75
|
+
</head>
|
|
76
|
+
)}
|
|
61
77
|
<body className={`${playfairDisplay.variable} ${plusJakartaSans.variable}`}>
|
|
62
78
|
<Script id="papyrus-favicon-color-scheme" strategy="beforeInteractive">
|
|
63
79
|
{`(() => {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { notFound, redirect } from "next/navigation";
|
|
2
|
+
import { toPublicNewsroomPath } from "../../../../lib/newsroom-base-path";
|
|
2
3
|
import { NewsDeskPage } from "../../../../components/news-desk-page";
|
|
3
4
|
import type { NewsDeskTab } from "../../../../components/topic-steering-workspace";
|
|
4
5
|
|
|
@@ -37,13 +38,13 @@ const NEWS_DESK_ROUTE_SECTIONS = new Set<NewsDeskTab>([
|
|
|
37
38
|
|
|
38
39
|
export default async function NewsDeskNestedSectionPage({ params, searchParams }: NewsDeskNestedSectionPageProps) {
|
|
39
40
|
const { section, selection } = await params;
|
|
40
|
-
if (section === "users") redirect("/newsroom/administration/users");
|
|
41
|
-
if (section === "doctrine") redirect("/newsroom/administration/policies");
|
|
42
|
-
if (section === "administration" && selection[0] === "analysis") redirect("/newsroom/assignments");
|
|
41
|
+
if (section === "users") redirect(toPublicNewsroomPath("/newsroom/administration/users"));
|
|
42
|
+
if (section === "doctrine") redirect(toPublicNewsroomPath("/newsroom/administration/policies"));
|
|
43
|
+
if (section === "administration" && selection[0] === "analysis") redirect(toPublicNewsroomPath("/newsroom/assignments"));
|
|
43
44
|
if (section === "desks") {
|
|
44
45
|
const category = selection[0] ? decodeURIComponent(selection[0]) : null;
|
|
45
|
-
if (category) redirect(`/newsroom/topics?category=${encodeURIComponent(category)}`);
|
|
46
|
-
redirect("/newsroom/topics");
|
|
46
|
+
if (category) redirect(toPublicNewsroomPath(`/newsroom/topics?category=${encodeURIComponent(category)}`));
|
|
47
|
+
redirect(toPublicNewsroomPath("/newsroom/topics"));
|
|
47
48
|
}
|
|
48
49
|
if (!NEWS_DESK_ROUTE_SECTIONS.has(section as NewsDeskTab)) notFound();
|
|
49
50
|
return <NewsDeskPage section={section} selectionPath={selection} searchParams={searchParams} />;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { notFound, redirect } from "next/navigation";
|
|
2
|
+
import { toPublicNewsroomPath } from "../../../lib/newsroom-base-path";
|
|
2
3
|
import { NewsDeskPage } from "../../../components/news-desk-page";
|
|
3
4
|
import type { NewsDeskTab } from "../../../components/topic-steering-workspace";
|
|
4
5
|
|
|
@@ -39,9 +40,9 @@ const NEWS_DESK_ROUTE_SECTIONS = new Set<NewsDeskTab>([
|
|
|
39
40
|
|
|
40
41
|
export default async function NewsDeskSectionPage({ params, searchParams }: NewsDeskSectionPageProps) {
|
|
41
42
|
const { section } = await params;
|
|
42
|
-
if (section === "users") redirect("/newsroom/administration/users");
|
|
43
|
-
if (section === "doctrine") redirect("/newsroom/administration/policies");
|
|
44
|
-
if (section === "desks") redirect("/newsroom/topics");
|
|
43
|
+
if (section === "users") redirect(toPublicNewsroomPath("/newsroom/administration/users"));
|
|
44
|
+
if (section === "doctrine") redirect(toPublicNewsroomPath("/newsroom/administration/policies"));
|
|
45
|
+
if (section === "desks") redirect(toPublicNewsroomPath("/newsroom/topics"));
|
|
45
46
|
if (!NEWS_DESK_ROUTE_SECTIONS.has(section as NewsDeskTab)) notFound();
|
|
46
47
|
return <NewsDeskPage section={section} searchParams={searchParams} />;
|
|
47
48
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { NewsroomArticleEditor } from "../../../../components/newsroom-article-editor";
|
|
2
|
+
|
|
3
|
+
export const dynamic = "force-dynamic";
|
|
4
|
+
|
|
5
|
+
type NewsroomArticleEditorPageProps = {
|
|
6
|
+
params: Promise<{ id: string }>;
|
|
7
|
+
searchParams?: Promise<{ demo?: string | string[] }>;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default async function NewsroomArticleEditorPage({ params, searchParams }: NewsroomArticleEditorPageProps) {
|
|
11
|
+
const { id } = await params;
|
|
12
|
+
const resolved = await searchParams;
|
|
13
|
+
const demoValue = Array.isArray(resolved?.demo) ? resolved?.demo[0] : resolved?.demo;
|
|
14
|
+
return <NewsroomArticleEditor articleId={decodeURIComponent(id)} demo={demoValue === "1"} />;
|
|
15
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { NewsroomArticlesView } from "../../../components/newsroom-articles-view";
|
|
2
|
+
|
|
3
|
+
export const dynamic = "force-dynamic";
|
|
4
|
+
|
|
5
|
+
type NewsroomArticlesPageProps = {
|
|
6
|
+
searchParams?: Promise<{ demo?: string | string[] }>;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default async function NewsroomArticlesPage({ searchParams }: NewsroomArticlesPageProps) {
|
|
10
|
+
const resolved = await searchParams;
|
|
11
|
+
const demoValue = Array.isArray(resolved?.demo) ? resolved?.demo[0] : resolved?.demo;
|
|
12
|
+
return <NewsroomArticlesView demo={demoValue === "1"} />;
|
|
13
|
+
}
|
package/app/newsroom/layout.tsx
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
1
|
+
// Component rules only (no reset, no theme): the Cyclotron review control and status widget.
|
|
2
|
+
import "cyclotron/styles/components.css";
|
|
3
|
+
import { NewsroomClientShell } from "../../components/newsroom-client-shell";
|
|
3
4
|
|
|
4
5
|
export default function NewsroomLayout({ children }: Readonly<{ children: React.ReactNode }>) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
return (
|
|
8
|
-
<NewsDeskClientProvider devSandboxEditorAuth={devSandboxEditorAuth}>
|
|
9
|
-
{children}
|
|
10
|
-
</NewsDeskClientProvider>
|
|
11
|
-
);
|
|
6
|
+
return <NewsroomClientShell>{children}</NewsroomClientShell>;
|
|
12
7
|
}
|
package/app/page.tsx
CHANGED
|
@@ -15,7 +15,10 @@ import {
|
|
|
15
15
|
} from "../lib/public-placeholder-config";
|
|
16
16
|
import type { PublicationItem } from "../lib/publication-items";
|
|
17
17
|
import { SITE_BRAND, rootRoute } from "../lib/site-brand";
|
|
18
|
-
import { redirect } from "next/navigation";
|
|
18
|
+
import { notFound, redirect } from "next/navigation";
|
|
19
|
+
import { getReaderBasePath } from "../lib/reader-base-path";
|
|
20
|
+
import { buildRootRedirectTarget } from "../lib/root-route-redirect";
|
|
21
|
+
import { NewsroomClientShell } from "../components/newsroom-client-shell";
|
|
19
22
|
import NewsDeskRootPage, { type NewsDeskRootSearchParams } from "./newsroom/page";
|
|
20
23
|
|
|
21
24
|
export const dynamic = "force-dynamic";
|
|
@@ -37,12 +40,22 @@ export default async function Home({ searchParams }: HomePageProps) {
|
|
|
37
40
|
// co-hosts reader + CMS uses the default "reader" (render the publication
|
|
38
41
|
// home page here). A CMS-only site points the root at the newsroom or
|
|
39
42
|
// anywhere else. Preserve the scenario and OAuth-callback paths.
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
const publicationOwnsRoot = getReaderBasePath() !== "";
|
|
44
|
+
|
|
45
|
+
if (!publicationOwnsRoot && rootRoute.kind === "newsroom" && !scenarioId) {
|
|
46
|
+
return (
|
|
47
|
+
<NewsroomClientShell>
|
|
48
|
+
<NewsDeskRootPage searchParams={searchParams} />
|
|
49
|
+
</NewsroomClientShell>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!publicationOwnsRoot && rootRoute.kind === "redirect") {
|
|
54
|
+
redirect(buildRootRedirectTarget(rootRoute.destination, resolvedSearchParams));
|
|
42
55
|
}
|
|
43
56
|
|
|
44
|
-
if (
|
|
45
|
-
|
|
57
|
+
if (SITE_BRAND.renderer.kind === "markus") {
|
|
58
|
+
notFound();
|
|
46
59
|
}
|
|
47
60
|
|
|
48
61
|
// Resolved only on the reader path: Markus brands (renderer "markus") have
|
package/app/robots.ts
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import type { MetadataRoute } from "next";
|
|
2
|
-
import {
|
|
2
|
+
import { buildRobots } from "../lib/robots-policy";
|
|
3
3
|
|
|
4
4
|
export const dynamic = "force-dynamic";
|
|
5
5
|
|
|
6
6
|
export default function robots(): MetadataRoute.Robots {
|
|
7
|
-
|
|
8
|
-
return { rules: { userAgent: "*", allow: "/" } };
|
|
9
|
-
}
|
|
10
|
-
return { rules: { userAgent: "*", disallow: "/" } };
|
|
7
|
+
return buildRobots();
|
|
11
8
|
}
|
package/bin/papyrus-app.mjs
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { sync } from "../src/sync.mjs";
|
|
3
3
|
|
|
4
|
-
const [command] = process.argv.slice(2);
|
|
4
|
+
const [command, ...rest] = process.argv.slice(2);
|
|
5
5
|
if (command === "sync") {
|
|
6
6
|
sync();
|
|
7
|
+
} else if (command === "videoml-bundle") {
|
|
8
|
+
const preview = rest.includes("--preview");
|
|
9
|
+
const { buildBrowserBundle } = await import("../scripts/videoml/build-browser-bundle.mjs");
|
|
10
|
+
const { buildPreviewBundle } = await import("../scripts/videoml/build-preview-bundle.mjs");
|
|
11
|
+
try {
|
|
12
|
+
await (preview ? buildPreviewBundle() : buildBrowserBundle());
|
|
13
|
+
} catch (error) {
|
|
14
|
+
console.error(error.message);
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
7
17
|
} else {
|
|
8
|
-
console.error("Usage: papyrus-app sync");
|
|
18
|
+
console.error("Usage: papyrus-app sync | papyrus-app videoml-bundle [--preview]");
|
|
9
19
|
process.exit(command ? 1 : 0);
|
|
10
20
|
}
|
package/bin/papyrus-infra.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* papyrus-infra synth --site infra/site.json [--out cdk.out] [--account A] [--region R]
|
|
4
|
+
* papyrus-infra synth --account-stack github-oidc [--out cdk.out] [--account A] [--region R]
|
|
4
5
|
* papyrus-infra print-buildspec --site infra/site.json --app cms-production|cms-staging|reader
|
|
5
6
|
* Synthesizes the app-shell stack for a publication from its own site.json, or
|
|
6
7
|
* prints one of the generated Amplify build specs. Synth only: deploying is a
|
|
@@ -10,10 +11,11 @@ import fs from "node:fs";
|
|
|
10
11
|
import path from "node:path";
|
|
11
12
|
import { createRequire } from "node:module";
|
|
12
13
|
import { buildSpecFor } from "../infra/build-specs.js";
|
|
13
|
-
import { parseSiteConfig } from "../infra/site-config.js";
|
|
14
|
+
import { parseSiteConfig, resolveStackName } from "../infra/site-config.js";
|
|
14
15
|
|
|
15
16
|
const USAGE = [
|
|
16
17
|
"Usage: papyrus-infra synth --site infra/site.json [--out cdk.out] [--account A] [--region R]",
|
|
18
|
+
" papyrus-infra synth --account-stack github-oidc [--out cdk.out] [--account A] [--region R]",
|
|
17
19
|
" papyrus-infra print-buildspec --site infra/site.json --app cms-production|cms-staging|reader",
|
|
18
20
|
].join("\n");
|
|
19
21
|
|
|
@@ -28,6 +30,30 @@ if (command !== "synth" && command !== "print-buildspec") {
|
|
|
28
30
|
process.exit(command ? 1 : 0);
|
|
29
31
|
}
|
|
30
32
|
|
|
33
|
+
const accountStack = opt("account-stack");
|
|
34
|
+
if (accountStack !== undefined) {
|
|
35
|
+
if (command !== "synth" || accountStack !== "github-oidc") {
|
|
36
|
+
console.error(USAGE);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
let GithubOidcProviderStack;
|
|
40
|
+
try {
|
|
41
|
+
({ GithubOidcProviderStack } = await import("../infra/index.js"));
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.error(`papyrus-infra: ${error instanceof Error ? error.message : error}`);
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
const { App } = createRequire(path.join(process.cwd(), "noop.js"))("aws-cdk-lib");
|
|
47
|
+
const app = new App({ outdir: path.resolve(opt("out", "cdk.out")) });
|
|
48
|
+
new GithubOidcProviderStack(app, "GithubOidcProviderStack", {
|
|
49
|
+
env: { account: opt("account", "335163751677"), region: opt("region", "us-east-1") },
|
|
50
|
+
stackName: "github-oidc-provider",
|
|
51
|
+
});
|
|
52
|
+
app.synth();
|
|
53
|
+
console.log(`synthesized github-oidc-provider -> ${path.resolve(opt("out", "cdk.out"))}`);
|
|
54
|
+
process.exit(0);
|
|
55
|
+
}
|
|
56
|
+
|
|
31
57
|
let config;
|
|
32
58
|
try {
|
|
33
59
|
config = parseSiteConfig(JSON.parse(fs.readFileSync(path.resolve(opt("site", "infra/site.json")), "utf8")));
|
|
@@ -63,7 +89,7 @@ const { App } = createRequire(path.join(process.cwd(), "noop.js"))("aws-cdk-lib"
|
|
|
63
89
|
const app = new App({ outdir: path.resolve(opt("out", "cdk.out")) });
|
|
64
90
|
new AmplifyAppShellStack(app, `AmplifyAppShell-${config.siteId}`, config, {
|
|
65
91
|
env: { account: opt("account", "335163751677"), region: opt("region", "us-east-1") },
|
|
66
|
-
stackName:
|
|
92
|
+
stackName: resolveStackName(config),
|
|
67
93
|
});
|
|
68
94
|
app.synth();
|
|
69
|
-
console.log(`synthesized
|
|
95
|
+
console.log(`synthesized ${resolveStackName(config)} -> ${path.resolve(opt("out", "cdk.out"))}`);
|