@anthusai/papyrus 1.0.0-next.8 → 1.0.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/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 +42 -80
- package/amplify/data/resource.ts +42 -80
- package/amplify/data/schema.js +45 -60
- package/amplify/data/schema.ts +47 -60
- 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 +143 -1
- package/amplify/functions/content-actions/requirements.txt +2 -1
- package/amplify/functions/content-actions/resource.js +6 -1
- package/amplify/functions/content-actions/resource.ts +9 -2
- package/amplify/functions/renditions/handler.py +120 -0
- package/amplify/functions/renditions/requirements.txt +4 -0
- package/amplify/functions/shared/python-bundle.js +42 -2
- package/amplify/functions/shared/python-bundle.ts +47 -2
- 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/plugins/registry.js +19 -0
- package/amplify/plugins/registry.ts +23 -0
- package/amplify/plugins/signup/function/handler.py +200 -0
- package/amplify/plugins/signup/function/resource.js +27 -0
- package/amplify/plugins/signup/function/resource.ts +35 -0
- package/amplify/plugins/signup/papyrus.plugin.js +59 -0
- package/amplify/plugins/signup/papyrus.plugin.ts +74 -0
- package/amplify/plugins/signup/schema.js +40 -0
- package/amplify/plugins/signup/schema.ts +41 -0
- package/amplify/plugins/signup/waf.js +48 -0
- package/amplify/plugins/signup/waf.ts +51 -0
- package/amplify/plugins/types.js +1 -0
- package/amplify/plugins/types.ts +39 -0
- package/amplify/plugins/wire.js +24 -0
- package/amplify/plugins/wire.ts +26 -0
- package/amplify/publication/default-publication.js +18 -0
- package/amplify/publication/default-publication.ts +20 -0
- package/amplify/publication/invalidation-alarm.js +26 -0
- package/amplify/publication/invalidation-alarm.ts +30 -0
- package/amplify/publication/redirect-and-index.js +37 -0
- package/amplify/publication/renditions-function.js +74 -0
- package/amplify/publication/renditions-function.ts +112 -0
- package/amplify/publication/renditions-settings.js +51 -0
- package/amplify/publication/renditions-settings.ts +58 -0
- package/amplify/publication/reproject-on-deploy.js +73 -0
- package/amplify/publication/reproject-on-deploy.ts +78 -0
- package/amplify/publication/s3-projection-settings.js +67 -0
- package/amplify/publication/s3-projection-settings.ts +101 -0
- package/amplify/publication/s3-projection.js +151 -0
- package/amplify/publication/s3-projection.ts +201 -0
- package/amplify/resolver-waves.js +26 -0
- package/amplify/resolver-waves.ts +34 -0
- package/amplify/revalidate-invalidation-settings.js +30 -0
- package/amplify/revalidate-invalidation-settings.ts +35 -0
- package/amplify/revalidate-secret-policy.js +13 -0
- package/amplify/revalidate-secret-policy.ts +19 -0
- package/amplify/site-backend-config.js +65 -1
- package/amplify/site-backend-config.ts +153 -2
- package/amplify/site-backend-names.js +103 -0
- package/amplify/site-backend-names.ts +166 -0
- package/amplify/site-backend.js +143 -176
- package/amplify/site-backend.ts +181 -201
- package/amplify/storage-backups/construct.js +31 -0
- package/amplify/storage-backups/construct.ts +47 -0
- package/app/[year]/[month]/[day]/[articleSlug]/page.tsx +8 -1
- package/app/[year]/[month]/[day]/edition-route-page.tsx +2 -0
- package/app/[year]/[month]/[day]/page/[pageNumber]/page.tsx +6 -1
- package/app/[year]/[month]/[day]/page.tsx +1 -1
- package/app/[year]/[month]/[day]/section/[sectionKey]/page.tsx +6 -1
- package/app/api/archive/editions/route.ts +1 -1
- package/app/api/cyclotron/priming-proof/route.ts +11 -0
- package/app/api/media/[...path]/route.ts +5 -16
- package/app/api/revalidate/route.ts +15 -7
- package/app/archive/page.tsx +1 -1
- package/app/articles/[slug]/page.tsx +7 -5
- package/app/blog-rhythm.css +278 -0
- package/app/cyclotron/page.tsx +13 -0
- package/app/globals.css +2 -0
- package/app/layout.tsx +16 -0
- package/app/newsroom/[section]/[...selection]/page.tsx +9 -6
- package/app/newsroom/[section]/page.tsx +6 -3
- package/app/newsroom/layout.tsx +4 -9
- package/app/newsroom/settings/page.tsx +6 -0
- package/app/newsroom/work/page.tsx +10 -0
- package/app/page.tsx +22 -8
- package/app/robots.ts +2 -5
- package/app/tailwind.css +1 -0
- package/bin/papyrus-infra.mjs +3 -3
- package/components/amplify-client-provider.tsx +5 -22
- package/components/archive-shell.tsx +2 -22
- package/components/article-video.tsx +152 -5
- package/components/blog-page-background.tsx +23 -6
- package/components/news-desk-page.tsx +4 -15
- package/components/news-desk-taxonomy-client.ts +90 -3
- package/components/newspaper.tsx +6 -2
- package/components/newsroom-access-gate.tsx +2 -1
- package/components/newsroom-board-view.tsx +99 -0
- package/components/newsroom-client-shell.tsx +12 -0
- package/components/newsroom-curation-provider.tsx +17 -0
- package/components/newsroom-fonts/playfair-display-700.ttf +0 -0
- package/components/newsroom-fonts/playfair-display-900.ttf +0 -0
- package/components/newsroom-fonts/playfair-display-OFL.txt +93 -0
- package/components/newsroom-fonts/plus-jakarta-sans-400.ttf +0 -0
- package/components/newsroom-fonts/plus-jakarta-sans-600.ttf +0 -0
- package/components/newsroom-fonts/plus-jakarta-sans-OFL.txt +93 -0
- package/components/newsroom-newsprint-board.css +48 -0
- package/components/newsroom-ops-overview.tsx +28 -11
- package/components/newsroom-ops-shell.tsx +7 -1
- package/components/newsroom-organizer-shell.tsx +130 -0
- package/components/newsroom-organizer.css +63 -0
- package/components/newsroom-references-view.tsx +92 -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/priming-proof-page.tsx +92 -0
- package/components/publication-cyclotron-panel.tsx +57 -0
- package/components/reader-auth-control.tsx +8 -5
- package/components/reference-curation-controls.tsx +77 -0
- package/components/reference-cyclotron-status.tsx +109 -0
- package/components/reference-priming.tsx +18 -0
- package/components/reference-relevance-review.tsx +75 -0
- package/components/settings-page.tsx +2 -1
- package/components/signup-entries-panel.tsx +94 -0
- package/components/topic-steering-workspace.tsx +78 -6
- package/components/use-blog-header-obstacles.ts +81 -0
- package/components/use-brand-fonts-ready.ts +28 -0
- package/components/use-near-viewport.ts +30 -0
- package/components/use-rhythm-overlay.ts +29 -0
- package/infra/amplify-app-shell.js +219 -71
- package/infra/amplify-app-shell.ts +231 -77
- package/infra/build-specs.js +23 -8
- package/infra/build-specs.ts +27 -11
- package/infra/site-config.js +277 -34
- package/infra/site-config.ts +340 -43
- package/lib/amplify-outputs-path.ts +5 -1
- package/lib/amplify-server-runtime.ts +36 -1
- package/lib/approved-priming-proof-reports.ts +6 -0
- 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 +43 -93
- package/lib/content-item-lifecycle.ts +55 -0
- package/lib/content-repository.ts +3 -0
- package/lib/content-types.ts +4 -0
- package/lib/curation-client.ts +61 -0
- package/lib/edition-routes.ts +31 -29
- package/lib/graphql-content-repository.ts +56 -22
- package/lib/media-route-response.ts +45 -0
- package/lib/newspaper-layout.ts +3 -2
- package/lib/newsroom-base-path.ts +12 -3
- package/lib/newsroom-board.ts +99 -0
- package/lib/newsroom-category-drilldown.ts +3 -2
- package/lib/newsroom-forum-routes.ts +6 -4
- package/lib/newsroom-index-filters.ts +14 -10
- package/lib/newsroom-nav.ts +3 -1
- package/lib/newsroom-organizer-nav.ts +37 -0
- package/lib/newsroom-section-routing.ts +20 -0
- package/lib/oauth-redirect-priority.ts +40 -0
- package/lib/papyrus-web-locations.ts +7 -6
- package/lib/plugin-settings.ts +11 -0
- package/lib/presentation-footer.ts +3 -2
- package/lib/pretext-layout.ts +12 -3
- package/lib/priming-proof-report.ts +89 -0
- package/lib/prospectus-site-identity.ts +303 -0
- package/lib/publication-cyclotron.ts +74 -0
- package/lib/rate-limit-retry.ts +55 -0
- package/lib/reader-base-path.ts +24 -0
- package/lib/reader-cache-lifetime.ts +5 -0
- package/lib/reader-static-params.ts +85 -4
- package/lib/reader-storage-url.ts +9 -12
- 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-prewarm.ts +53 -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/shared-credentials-provider.ts +61 -0
- package/lib/signup-csv.ts +24 -0
- package/lib/site-brand.ts +59 -0
- package/lib/staging-gated-path.ts +23 -0
- package/lib/staging-preview-object.ts +21 -5
- package/lib/test-editor-override.ts +4 -0
- package/lib/video-loading.ts +22 -0
- package/lib/video-script.ts +14 -0
- package/middleware.ts +11 -19
- package/package.json +64 -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 +68 -12
- package/src/sync.mjs +30 -6
- package/src/with-papyrus.d.mts +9 -0
- package/src/with-papyrus.mjs +48 -3
- 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
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import Link from "next/link";
|
|
4
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
5
|
+
import { solveFeaturedItem } from "../../lib/blog-feature-solver";
|
|
6
|
+
import { createDefaultBlogTextStyle, getMeasuredTextHeight, reserveRhythmRows } from "../../lib/blog-rhythm";
|
|
7
|
+
import type { ArticleVideoAsset } from "../../lib/articles";
|
|
8
|
+
import type { EditionContent, EditionSection } from "../../lib/content-types";
|
|
9
|
+
import { getEditionSectionItems } from "../../lib/edition-sections";
|
|
10
|
+
import { layoutAllTextLines, prepareWithSegments } from "../../lib/pretext-layout";
|
|
11
|
+
import { buildPresentationFooterEntries } from "../../lib/presentation-footer";
|
|
12
|
+
import {
|
|
13
|
+
getPublicationItemImageAssets,
|
|
14
|
+
getPublicationItemVideoAsset,
|
|
15
|
+
type PublicationItem,
|
|
16
|
+
} from "../../lib/publication-items";
|
|
17
|
+
import { SITE_BRAND } from "../../lib/site-brand";
|
|
18
|
+
import { EDITION_OVERVIEW_VIDEO_KEY, type VideoScriptRef } from "../../lib/video-script";
|
|
19
|
+
import { ArticleVideoFigure } from "../../components/article-video";
|
|
20
|
+
import { BlogPageBackground as GenericBlogPageBackground } from "../../components/blog-page-background";
|
|
21
|
+
import { PictogramFigure as GenericPictogramFigure } from "../../components/pictogram-figure";
|
|
22
|
+
import { PresentationFooter } from "../../components/presentation-footer";
|
|
23
|
+
import { getSectionAnchorId, PresentationHeader } from "../../components/presentation-header";
|
|
24
|
+
import { PresentationRhythmHRule } from "../../components/presentation-rhythm-hrule";
|
|
25
|
+
import { useBlogHeaderObstacles } from "../../components/use-blog-header-obstacles";
|
|
26
|
+
import { useBrandFontsReadyVersion } from "../../components/use-brand-fonts-ready";
|
|
27
|
+
import { useRhythmOverlay } from "../../components/use-rhythm-overlay";
|
|
28
|
+
import {
|
|
29
|
+
getBlogFooterSectionHref,
|
|
30
|
+
getPresentationBodyText,
|
|
31
|
+
getPresentationItemRole,
|
|
32
|
+
getPresentationTitle,
|
|
33
|
+
handleBlogFooterSectionClick,
|
|
34
|
+
MeasuredPresentationLines,
|
|
35
|
+
useMeasuredWidth,
|
|
36
|
+
usePresentationTargetScroll,
|
|
37
|
+
} from "./presentation-shared";
|
|
38
|
+
import { BLOG_RHYTHM, getFeaturedLayoutStyle, getRhythmShellStyle } from "./rhythm-shell-style";
|
|
39
|
+
|
|
40
|
+
const BlogPageBackground = SITE_BRAND.components?.BlogPageBackground ?? GenericBlogPageBackground;
|
|
41
|
+
const PictogramFigure = SITE_BRAND.components?.PictogramFigure ?? GenericPictogramFigure;
|
|
42
|
+
const BLOG_TEXT_STYLE = createDefaultBlogTextStyle(SITE_BRAND.textFont);
|
|
43
|
+
const SECONDARY_PAIR_ITEM_INDEX = 2;
|
|
44
|
+
|
|
45
|
+
type PapyrusTestWindow = Window & typeof globalThis & {
|
|
46
|
+
__PAPYRUS_SCENARIO__?: string;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export function RhythmBlogPresentation({
|
|
50
|
+
content,
|
|
51
|
+
editionBasePath,
|
|
52
|
+
targetSection,
|
|
53
|
+
}: {
|
|
54
|
+
content: EditionContent;
|
|
55
|
+
editionBasePath?: string;
|
|
56
|
+
targetSection?: EditionSection;
|
|
57
|
+
}) {
|
|
58
|
+
const footerEntries = useMemo(() => buildPresentationFooterEntries(content), [content]);
|
|
59
|
+
const footerSubtitle = SITE_BRAND.id === "papyrus" ? (content.description?.trim() || "Inside Papyrus") : SITE_BRAND.mastheadSubtitle;
|
|
60
|
+
const pageRef = useRef<HTMLElement | null>(null);
|
|
61
|
+
const showRhythmOverlay = useRhythmOverlay();
|
|
62
|
+
const headerObstacles = useBlogHeaderObstacles(pageRef, BLOG_RHYTHM.paintBuffer);
|
|
63
|
+
usePresentationTargetScroll(targetSection);
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
(window as PapyrusTestWindow).__PAPYRUS_SCENARIO__ = content.scenarioId;
|
|
66
|
+
return () => {
|
|
67
|
+
delete (window as PapyrusTestWindow).__PAPYRUS_SCENARIO__;
|
|
68
|
+
};
|
|
69
|
+
}, [content.scenarioId]);
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<main
|
|
73
|
+
className="presentation-page presentation-page--blog blog-rhythm-shell"
|
|
74
|
+
data-presentation-engine="blog"
|
|
75
|
+
data-rhythm-overlay={showRhythmOverlay ? "true" : "false"}
|
|
76
|
+
ref={pageRef}
|
|
77
|
+
style={getRhythmShellStyle(BLOG_RHYTHM)}
|
|
78
|
+
>
|
|
79
|
+
<BlogPageBackground headerObstacles={headerObstacles} pageRef={pageRef} rhythm={BLOG_RHYTHM} />
|
|
80
|
+
<PresentationHeader
|
|
81
|
+
description={content.description}
|
|
82
|
+
editionBasePath={editionBasePath}
|
|
83
|
+
editionDate={content.editionDate}
|
|
84
|
+
sections={content.sections}
|
|
85
|
+
title={content.title}
|
|
86
|
+
/>
|
|
87
|
+
<div className="blog-sections">
|
|
88
|
+
{content.sections.map((section, sectionIndex) => (
|
|
89
|
+
<section className="blog-section" data-edition-section={section.key} id={getSectionAnchorId(section.key)} key={section.key}>
|
|
90
|
+
{sectionIndex === 0 && content.editionVideo ? (
|
|
91
|
+
<EditionOverviewVideo
|
|
92
|
+
editionVideo={content.editionVideo}
|
|
93
|
+
videoScript={content.videoScripts?.[EDITION_OVERVIEW_VIDEO_KEY] ?? null}
|
|
94
|
+
/>
|
|
95
|
+
) : null}
|
|
96
|
+
<header className="presentation-section-header">
|
|
97
|
+
<div className="presentation-section-header__band">
|
|
98
|
+
<p>{section.label}</p>
|
|
99
|
+
</div>
|
|
100
|
+
{section.description ? <span>{section.description}</span> : null}
|
|
101
|
+
</header>
|
|
102
|
+
{getEditionSectionItems(section, content.items).flatMap((item, index) => [
|
|
103
|
+
...(index > 0
|
|
104
|
+
? [
|
|
105
|
+
<PresentationRhythmHRule
|
|
106
|
+
hideInSecondaryPair={index === SECONDARY_PAIR_ITEM_INDEX}
|
|
107
|
+
key={`hrule-before-${item.slug}`}
|
|
108
|
+
/>,
|
|
109
|
+
]
|
|
110
|
+
: []),
|
|
111
|
+
<RhythmPresentationItem
|
|
112
|
+
editionBasePath={editionBasePath}
|
|
113
|
+
index={index}
|
|
114
|
+
item={item}
|
|
115
|
+
key={item.slug}
|
|
116
|
+
videoScript={content.videoScripts?.[item.slug] ?? null}
|
|
117
|
+
/>,
|
|
118
|
+
])}
|
|
119
|
+
</section>
|
|
120
|
+
))}
|
|
121
|
+
</div>
|
|
122
|
+
<PresentationFooter
|
|
123
|
+
editionBasePath={editionBasePath}
|
|
124
|
+
entries={footerEntries}
|
|
125
|
+
onSectionClick={handleBlogFooterSectionClick}
|
|
126
|
+
resolveSectionHref={(entry) => getBlogFooterSectionHref(entry, editionBasePath)}
|
|
127
|
+
subtitle={SITE_BRAND.footerSubtitleOverride ?? footerSubtitle}
|
|
128
|
+
title={SITE_BRAND.footerTitle}
|
|
129
|
+
/>
|
|
130
|
+
</main>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function EditionOverviewVideo({
|
|
135
|
+
editionVideo,
|
|
136
|
+
videoScript,
|
|
137
|
+
}: {
|
|
138
|
+
editionVideo: ArticleVideoAsset;
|
|
139
|
+
videoScript: VideoScriptRef | null;
|
|
140
|
+
}) {
|
|
141
|
+
return (
|
|
142
|
+
<section className="presentation-edition-video" aria-label={editionVideo.alt}>
|
|
143
|
+
<ArticleVideoFigure
|
|
144
|
+
figureClassName="presentation-edition-video__figure article-video"
|
|
145
|
+
slug={EDITION_OVERVIEW_VIDEO_KEY}
|
|
146
|
+
video={editionVideo}
|
|
147
|
+
videoScript={videoScript}
|
|
148
|
+
/>
|
|
149
|
+
</section>
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function RhythmPresentationItem({
|
|
154
|
+
editionBasePath,
|
|
155
|
+
index,
|
|
156
|
+
item,
|
|
157
|
+
videoScript,
|
|
158
|
+
}: {
|
|
159
|
+
editionBasePath?: string;
|
|
160
|
+
index: number;
|
|
161
|
+
item: PublicationItem;
|
|
162
|
+
videoScript: VideoScriptRef | null;
|
|
163
|
+
}) {
|
|
164
|
+
const articleRef = useRef<HTMLElement | null>(null);
|
|
165
|
+
const frameRef = useRef<HTMLDivElement | null>(null);
|
|
166
|
+
const containerWidth = useMeasuredWidth(articleRef);
|
|
167
|
+
const frameWidth = useMeasuredWidth(frameRef);
|
|
168
|
+
const viewportWidth = useViewportWidth();
|
|
169
|
+
const fontsReadyVersion = useBrandFontsReadyVersion();
|
|
170
|
+
const textStyle = useMemo(() => ({ ...BLOG_TEXT_STYLE, fontsReadyVersion }), [fontsReadyVersion]);
|
|
171
|
+
const image = getPublicationItemImageAssets(item)[0];
|
|
172
|
+
const video = getPublicationItemVideoAsset(item);
|
|
173
|
+
const text = getPresentationBodyText(item, "blog");
|
|
174
|
+
const hasImage = Boolean(image);
|
|
175
|
+
const featuredLayout = useMemo(() => {
|
|
176
|
+
if (!hasImage || !containerWidth || !image) return null;
|
|
177
|
+
return solveFeaturedItem({
|
|
178
|
+
text,
|
|
179
|
+
containerWidth,
|
|
180
|
+
viewportWidth,
|
|
181
|
+
rhythm: BLOG_RHYTHM,
|
|
182
|
+
textStyle,
|
|
183
|
+
imageAsset: image,
|
|
184
|
+
itemIndex: index,
|
|
185
|
+
});
|
|
186
|
+
}, [containerWidth, hasImage, image, index, text, textStyle, viewportWidth]);
|
|
187
|
+
const lines = useMemo(() => {
|
|
188
|
+
if (featuredLayout) return featuredLayout.textLines;
|
|
189
|
+
const maxWidth = frameWidth || containerWidth;
|
|
190
|
+
if (!maxWidth || !text.trim()) return [];
|
|
191
|
+
return layoutAllTextLines({
|
|
192
|
+
prepared: prepareWithSegments(text, `${textStyle.fontSize}px ${textStyle.fontFamily}`, { whiteSpace: "pre-wrap" }),
|
|
193
|
+
maxWidth,
|
|
194
|
+
...textStyle,
|
|
195
|
+
});
|
|
196
|
+
}, [containerWidth, featuredLayout, frameWidth, text, textStyle]);
|
|
197
|
+
const textHeight = featuredLayout?.textFrameHeight ?? reserveRhythmRows(getMeasuredTextHeight(lines), BLOG_RHYTHM);
|
|
198
|
+
const layoutMode = featuredLayout?.mode ?? "stacked";
|
|
199
|
+
const directHref = editionBasePath ? `${editionBasePath}/${encodeURIComponent(item.slug)}` : `/articles/${encodeURIComponent(item.slug)}`;
|
|
200
|
+
|
|
201
|
+
return (
|
|
202
|
+
<article
|
|
203
|
+
className="presentation-item presentation-item--blog"
|
|
204
|
+
data-feature-layout={hasImage ? layoutMode : undefined}
|
|
205
|
+
data-has-image={hasImage ? "true" : "false"}
|
|
206
|
+
data-has-video={video ? "true" : "false"}
|
|
207
|
+
data-item-id={item.slug}
|
|
208
|
+
data-item-index={index}
|
|
209
|
+
data-item-role={getPresentationItemRole("blog", index)}
|
|
210
|
+
data-item-type={item.type}
|
|
211
|
+
id={item.slug}
|
|
212
|
+
ref={articleRef}
|
|
213
|
+
style={featuredLayout ? getFeaturedLayoutStyle(featuredLayout) : undefined}
|
|
214
|
+
>
|
|
215
|
+
<div className="presentation-item__copy">
|
|
216
|
+
<header className="presentation-item__header">
|
|
217
|
+
<p>{item.section ?? "General"}</p>
|
|
218
|
+
<h2>
|
|
219
|
+
<Link href={directHref}>{getPresentationTitle(item)}</Link>
|
|
220
|
+
</h2>
|
|
221
|
+
{item.deck ? <span>{item.deck}</span> : null}
|
|
222
|
+
</header>
|
|
223
|
+
<div className="presentation-item__body">
|
|
224
|
+
{image ? (
|
|
225
|
+
<div className="presentation-item__media">
|
|
226
|
+
<PictogramFigure
|
|
227
|
+
alt={image.alt}
|
|
228
|
+
caption={image.caption}
|
|
229
|
+
credit={image.credit}
|
|
230
|
+
figureClassName="presentation-item__image"
|
|
231
|
+
frameHeight={featuredLayout?.imageHeight}
|
|
232
|
+
frameWidth={featuredLayout?.imageWidth}
|
|
233
|
+
height={760}
|
|
234
|
+
layout={image.layout}
|
|
235
|
+
sizes="(max-width: 900px) 100vw, 760px"
|
|
236
|
+
slug={item.slug}
|
|
237
|
+
src={image.src}
|
|
238
|
+
themeVariants={image.themeVariants}
|
|
239
|
+
width={1200}
|
|
240
|
+
/>
|
|
241
|
+
</div>
|
|
242
|
+
) : null}
|
|
243
|
+
<div
|
|
244
|
+
className="presentation-item__text-frame"
|
|
245
|
+
data-layout-mode={layoutMode}
|
|
246
|
+
ref={frameRef}
|
|
247
|
+
style={{ height: textHeight }}
|
|
248
|
+
>
|
|
249
|
+
<MeasuredPresentationLines lines={lines} />
|
|
250
|
+
</div>
|
|
251
|
+
<Link className="presentation-item__cta" href={directHref}>
|
|
252
|
+
Read Article
|
|
253
|
+
</Link>
|
|
254
|
+
</div>
|
|
255
|
+
</div>
|
|
256
|
+
{video ? (
|
|
257
|
+
<div className="presentation-item__video">
|
|
258
|
+
<ArticleVideoFigure
|
|
259
|
+
figureClassName="presentation-item__video-figure article-video"
|
|
260
|
+
slug={item.slug}
|
|
261
|
+
video={video}
|
|
262
|
+
videoScript={videoScript}
|
|
263
|
+
/>
|
|
264
|
+
</div>
|
|
265
|
+
) : null}
|
|
266
|
+
</article>
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function useViewportWidth(): number {
|
|
271
|
+
const [width, setWidth] = useState(0);
|
|
272
|
+
useEffect(() => {
|
|
273
|
+
const update = () => setWidth(Math.max(1, Math.floor(window.innerWidth)));
|
|
274
|
+
update();
|
|
275
|
+
window.addEventListener("resize", update);
|
|
276
|
+
return () => window.removeEventListener("resize", update);
|
|
277
|
+
}, []);
|
|
278
|
+
return width;
|
|
279
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { CSSProperties } from "react";
|
|
2
|
+
import {
|
|
3
|
+
BLOG_COPY_ROW_MULTIPLE,
|
|
4
|
+
createDefaultBlogVerticalRhythm,
|
|
5
|
+
type VerticalRhythm,
|
|
6
|
+
} from "../../lib/blog-rhythm";
|
|
7
|
+
|
|
8
|
+
export const BLOG_RHYTHM: VerticalRhythm = createDefaultBlogVerticalRhythm();
|
|
9
|
+
|
|
10
|
+
export function getRhythmShellStyle(rhythm: VerticalRhythm): CSSProperties {
|
|
11
|
+
return {
|
|
12
|
+
"--blog-rhythm": `${rhythm.rowHeight / BLOG_COPY_ROW_MULTIPLE}px`,
|
|
13
|
+
"--blog-row-height": `${rhythm.rowHeight}px`,
|
|
14
|
+
"--blog-paint-buffer": `${rhythm.paintBuffer}px`,
|
|
15
|
+
"--blog-paint-height": `${rhythm.paintHeight}px`,
|
|
16
|
+
} as CSSProperties;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function getFeaturedLayoutStyle(layout: {
|
|
20
|
+
copyWidth: number;
|
|
21
|
+
imageWidth: number;
|
|
22
|
+
imageHeight: number;
|
|
23
|
+
gap: number;
|
|
24
|
+
mediaHeight?: number;
|
|
25
|
+
textFrameHeight?: number;
|
|
26
|
+
}): CSSProperties {
|
|
27
|
+
return {
|
|
28
|
+
"--feature-copy-width": `${layout.copyWidth}px`,
|
|
29
|
+
"--feature-image-width": `${layout.imageWidth}px`,
|
|
30
|
+
"--feature-image-height": `${layout.imageHeight}px`,
|
|
31
|
+
"--feature-layout-gap": `${layout.gap}px`,
|
|
32
|
+
...(layout.mediaHeight === undefined ? {} : { "--feature-media-height": `${layout.mediaHeight}px` }),
|
|
33
|
+
...(layout.textFrameHeight === undefined ? {} : { "--feature-text-frame-height": `${layout.textFrameHeight}px` }),
|
|
34
|
+
} as CSSProperties;
|
|
35
|
+
}
|
package/routes.manifest.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.0.0
|
|
2
|
+
"version": "1.0.0",
|
|
3
3
|
"routes": [
|
|
4
4
|
{
|
|
5
5
|
"file": "app/%5F_preview/[[...path]]/route.ts",
|
|
@@ -13,38 +13,47 @@
|
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
"file": "app/[year]/[month]/[day]/[articleSlug]/page.tsx",
|
|
16
|
+
"reader": true,
|
|
16
17
|
"hasDefault": true,
|
|
17
18
|
"exports": [
|
|
18
|
-
"generateMetadata"
|
|
19
|
+
"generateMetadata",
|
|
20
|
+
"generateStaticParams"
|
|
19
21
|
],
|
|
20
22
|
"config": {
|
|
21
|
-
"revalidate": "
|
|
23
|
+
"revalidate": "60"
|
|
22
24
|
}
|
|
23
25
|
},
|
|
24
26
|
{
|
|
25
27
|
"file": "app/[year]/[month]/[day]/page.tsx",
|
|
28
|
+
"reader": true,
|
|
26
29
|
"hasDefault": true,
|
|
27
30
|
"exports": [
|
|
28
31
|
"generateStaticParams"
|
|
29
32
|
],
|
|
30
33
|
"config": {
|
|
31
|
-
"revalidate": "
|
|
34
|
+
"revalidate": "60"
|
|
32
35
|
}
|
|
33
36
|
},
|
|
34
37
|
{
|
|
35
38
|
"file": "app/[year]/[month]/[day]/page/[pageNumber]/page.tsx",
|
|
39
|
+
"reader": true,
|
|
36
40
|
"hasDefault": true,
|
|
37
|
-
"exports": [
|
|
41
|
+
"exports": [
|
|
42
|
+
"generateStaticParams"
|
|
43
|
+
],
|
|
38
44
|
"config": {
|
|
39
|
-
"revalidate": "
|
|
45
|
+
"revalidate": "60"
|
|
40
46
|
}
|
|
41
47
|
},
|
|
42
48
|
{
|
|
43
49
|
"file": "app/[year]/[month]/[day]/section/[sectionKey]/page.tsx",
|
|
50
|
+
"reader": true,
|
|
44
51
|
"hasDefault": true,
|
|
45
|
-
"exports": [
|
|
52
|
+
"exports": [
|
|
53
|
+
"generateStaticParams"
|
|
54
|
+
],
|
|
46
55
|
"config": {
|
|
47
|
-
"revalidate": "
|
|
56
|
+
"revalidate": "60"
|
|
48
57
|
}
|
|
49
58
|
},
|
|
50
59
|
{
|
|
@@ -54,9 +63,17 @@
|
|
|
54
63
|
"GET"
|
|
55
64
|
],
|
|
56
65
|
"config": {
|
|
57
|
-
"revalidate": "
|
|
66
|
+
"revalidate": "60"
|
|
58
67
|
}
|
|
59
68
|
},
|
|
69
|
+
{
|
|
70
|
+
"file": "app/api/cyclotron/priming-proof/route.ts",
|
|
71
|
+
"hasDefault": false,
|
|
72
|
+
"exports": [
|
|
73
|
+
"GET"
|
|
74
|
+
],
|
|
75
|
+
"config": {}
|
|
76
|
+
},
|
|
60
77
|
{
|
|
61
78
|
"file": "app/api/media/[...path]/route.ts",
|
|
62
79
|
"hasDefault": false,
|
|
@@ -79,23 +96,33 @@
|
|
|
79
96
|
},
|
|
80
97
|
{
|
|
81
98
|
"file": "app/archive/page.tsx",
|
|
99
|
+
"reader": true,
|
|
82
100
|
"hasDefault": true,
|
|
83
101
|
"exports": [],
|
|
84
102
|
"config": {
|
|
85
|
-
"revalidate": "
|
|
103
|
+
"revalidate": "60"
|
|
86
104
|
}
|
|
87
105
|
},
|
|
88
106
|
{
|
|
89
107
|
"file": "app/articles/[slug]/page.tsx",
|
|
108
|
+
"reader": true,
|
|
90
109
|
"hasDefault": true,
|
|
91
110
|
"exports": [
|
|
92
111
|
"generateMetadata",
|
|
93
112
|
"generateStaticParams"
|
|
94
113
|
],
|
|
95
114
|
"config": {
|
|
96
|
-
"revalidate": "
|
|
115
|
+
"revalidate": "60"
|
|
97
116
|
}
|
|
98
117
|
},
|
|
118
|
+
{
|
|
119
|
+
"file": "app/cyclotron/page.tsx",
|
|
120
|
+
"hasDefault": true,
|
|
121
|
+
"exports": [
|
|
122
|
+
"metadata"
|
|
123
|
+
],
|
|
124
|
+
"config": {}
|
|
125
|
+
},
|
|
99
126
|
{
|
|
100
127
|
"file": "app/layout.tsx",
|
|
101
128
|
"hasDefault": true,
|
|
@@ -182,8 +209,35 @@
|
|
|
182
209
|
"dynamic": "\"force-dynamic\""
|
|
183
210
|
}
|
|
184
211
|
},
|
|
212
|
+
{
|
|
213
|
+
"file": "app/newsroom/settings/page.tsx",
|
|
214
|
+
"hasDefault": true,
|
|
215
|
+
"exports": [
|
|
216
|
+
"metadata"
|
|
217
|
+
],
|
|
218
|
+
"config": {
|
|
219
|
+
"dynamic": "\"force-dynamic\""
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
"file": "app/newsroom/work/page.tsx",
|
|
224
|
+
"hasDefault": true,
|
|
225
|
+
"exports": [],
|
|
226
|
+
"config": {
|
|
227
|
+
"dynamic": "\"force-dynamic\""
|
|
228
|
+
}
|
|
229
|
+
},
|
|
185
230
|
{
|
|
186
231
|
"file": "app/page.tsx",
|
|
232
|
+
"reader": true,
|
|
233
|
+
"hasDefault": true,
|
|
234
|
+
"exports": [],
|
|
235
|
+
"config": {
|
|
236
|
+
"dynamic": "\"force-dynamic\""
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
"file": "app/robots.ts",
|
|
187
241
|
"hasDefault": true,
|
|
188
242
|
"exports": [],
|
|
189
243
|
"config": {
|
|
@@ -192,6 +246,7 @@
|
|
|
192
246
|
},
|
|
193
247
|
{
|
|
194
248
|
"file": "app/settings/page.tsx",
|
|
249
|
+
"reader": true,
|
|
195
250
|
"hasDefault": true,
|
|
196
251
|
"exports": [
|
|
197
252
|
"metadata"
|
|
@@ -203,6 +258,7 @@
|
|
|
203
258
|
],
|
|
204
259
|
"middleware": {
|
|
205
260
|
"file": "middleware.ts",
|
|
206
|
-
"matcher": "[\"/((?!_next/static|_next/image|favicon.ico|icon).*)\"]"
|
|
261
|
+
"matcher": "[\"/((?!_next/static|_next/image|favicon.ico|icon).*)\"]",
|
|
262
|
+
"runtime": "nodejs"
|
|
207
263
|
}
|
|
208
264
|
}
|
package/src/sync.mjs
CHANGED
|
@@ -37,18 +37,42 @@ function shimFor(route) {
|
|
|
37
37
|
return lines.join("\n") + "\n";
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
function middlewareShim(manifest) {
|
|
40
|
+
export function middlewareShim(manifest) {
|
|
41
41
|
const matcher = manifest.middleware.matcher ?? '["/((?!_next/static|_next/image|favicon.ico|icon).*)"]';
|
|
42
42
|
return [
|
|
43
43
|
MARKER,
|
|
44
44
|
`export { middleware } from "${PKG}/middleware";`,
|
|
45
|
-
`export const config = { matcher: ${matcher} };`,
|
|
45
|
+
`export const config = { ${manifest.middleware.runtime ? `runtime: ${JSON.stringify(manifest.middleware.runtime)}, ` : ""}matcher: ${matcher} };`,
|
|
46
46
|
"",
|
|
47
47
|
].join("\n");
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
const RESERVED_FIRST_SEGMENTS = new Set(["newsroom", "api", "_next", "_preview", "%5F_preview"]);
|
|
51
|
+
|
|
52
|
+
export function normalizeReaderBasePath(value) {
|
|
53
|
+
const trimmed = (value ?? "").trim().replace(/\/+$/, "");
|
|
54
|
+
if (!trimmed) return "";
|
|
55
|
+
return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function readReaderBasePath(root) {
|
|
59
|
+
let text;
|
|
60
|
+
try {
|
|
61
|
+
text = fs.readFileSync(path.join(root, "papyrus.config.ts"), "utf8");
|
|
62
|
+
} catch {
|
|
63
|
+
return "";
|
|
64
|
+
}
|
|
65
|
+
const match = text.match(/\breaderBasePath\s*:\s*(["'`])([^"'`]*)\1/);
|
|
66
|
+
return normalizeReaderBasePath(match ? match[2] : "");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function sync({ root = process.cwd(), log = console.log, manifest: manifestOverride, readerBasePath: readerBasePathOverride } = {}) {
|
|
70
|
+
const manifest = manifestOverride ?? JSON.parse(fs.readFileSync(path.join(pkgRoot, "routes.manifest.json"), "utf8"));
|
|
71
|
+
const readerBasePath = normalizeReaderBasePath(readerBasePathOverride ?? readReaderBasePath(root));
|
|
72
|
+
if (readerBasePath && RESERVED_FIRST_SEGMENTS.has(readerBasePath.split("/")[1])) {
|
|
73
|
+
throw new Error(`readerBasePath "${readerBasePath}" collides with a Papyrus-owned route (newsroom, api, _preview)`);
|
|
74
|
+
}
|
|
75
|
+
const readerRouteFile = (file) => (readerBasePath ? file.replace(/^app\//, `app${readerBasePath}/`) : file);
|
|
52
76
|
const generated = [];
|
|
53
77
|
const skipped = [];
|
|
54
78
|
const write = (relPath, content) => {
|
|
@@ -61,7 +85,7 @@ export function sync({ root = process.cwd(), log = console.log } = {}) {
|
|
|
61
85
|
fs.writeFileSync(dest, content);
|
|
62
86
|
generated.push(relPath);
|
|
63
87
|
};
|
|
64
|
-
for (const route of manifest.routes) write(route.file, shimFor(route));
|
|
88
|
+
for (const route of manifest.routes) write(route.reader ? readerRouteFile(route.file) : route.file, shimFor(route));
|
|
65
89
|
write("middleware.ts", middlewareShim(manifest));
|
|
66
90
|
|
|
67
91
|
// Remove shims that are no longer in the manifest (e.g. after an upgrade).
|
|
@@ -81,7 +105,7 @@ export function sync({ root = process.cwd(), log = console.log } = {}) {
|
|
|
81
105
|
const re = new RegExp(`${GITIGNORE_BEGIN.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[\\s\\S]*?${GITIGNORE_END}`);
|
|
82
106
|
fs.writeFileSync(giFile, re.test(gi) ? gi.replace(re, block) : `${gi}${gi.endsWith("\n") || !gi ? "" : "\n"}${block}\n`);
|
|
83
107
|
|
|
84
|
-
log(`papyrus-app sync: ${generated.length} shim(s) written, ${skipped.length} site-owned file(s) kept (${PKG}@${manifest.version})`);
|
|
108
|
+
log(`papyrus-app sync: ${generated.length} shim(s) written, ${skipped.length} site-owned file(s) kept (${PKG}@${manifest.version})${readerBasePath ? `, reader mounted at ${readerBasePath}` : ""}`);
|
|
85
109
|
for (const rel of skipped) log(` site-owned: ${rel}`);
|
|
86
110
|
return { generated, skipped };
|
|
87
111
|
}
|
package/src/with-papyrus.d.mts
CHANGED
|
@@ -1,2 +1,11 @@
|
|
|
1
1
|
import type { NextConfig } from "next";
|
|
2
2
|
export function withPapyrus(nextConfig?: NextConfig, options?: { root?: string }): NextConfig;
|
|
3
|
+
export const READER_EXPIRE_TIME_SECONDS: number;
|
|
4
|
+
export const DEFAULT_STATIC_GENERATION_WORKERS: number;
|
|
5
|
+
export const DEFAULT_STATIC_GENERATION_CONCURRENCY: number;
|
|
6
|
+
export const DEFAULT_STATIC_GENERATION_RETRY_COUNT: number;
|
|
7
|
+
export function staticGenerationSettings(): {
|
|
8
|
+
cpus: number;
|
|
9
|
+
staticGenerationMaxConcurrency: number;
|
|
10
|
+
staticGenerationRetryCount: number;
|
|
11
|
+
};
|
package/src/with-papyrus.mjs
CHANGED
|
@@ -4,11 +4,14 @@ import { fileURLToPath } from "node:url";
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Wrap a publication repo's Next config for Papyrus (SPIKE, PPY-82be6c).
|
|
7
|
-
* - transpile the package
|
|
7
|
+
* - transpile the package and the dependencies that ship TypeScript source (cyclotron),
|
|
8
8
|
* - alias `papyrus-site` -> ./papyrus.config.ts,
|
|
9
9
|
* `papyrus-amplify-outputs` -> ./amplify_outputs.json and
|
|
10
10
|
* `papyrus-site-theme` -> ./publication/theme.css when it exists, else the shipped
|
|
11
11
|
* empty lib/empty-theme.css (both webpack and turbopack),
|
|
12
|
+
* - trace the corpora/ YAML and amplify_outputs.json that the reader reads via fs at runtime,
|
|
13
|
+
* - cap static generation at 2 workers x 3 pages (override with PAPYRUS_STATIC_GENERATION_WORKERS / _CONCURRENCY) and retry
|
|
14
|
+
* failed pages 3 times, so pre-building the reader pages stays under Cognito guest-credential throttles,
|
|
12
15
|
* - carry Papyrus's own server-external packages and image settings.
|
|
13
16
|
*/
|
|
14
17
|
const SERVER_EXTERNAL = [
|
|
@@ -22,6 +25,46 @@ const SERVER_EXTERNAL = [
|
|
|
22
25
|
"@aws-amplify/data-schema",
|
|
23
26
|
];
|
|
24
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Next sends `stale-while-revalidate` = `expireTime` - `revalidate` (one year by default), so a shared cache may serve a
|
|
30
|
+
* page for a year past its `s-maxage` while it refreshes in the background. Twice the reader's 60 s page lifetime
|
|
31
|
+
* (lib/reader-cache-lifetime.ts) bounds that to 60 s.
|
|
32
|
+
*/
|
|
33
|
+
export const READER_EXPIRE_TIME_SECONDS = 120;
|
|
34
|
+
|
|
35
|
+
export const DEFAULT_STATIC_GENERATION_WORKERS = 2;
|
|
36
|
+
export const DEFAULT_STATIC_GENERATION_CONCURRENCY = 3;
|
|
37
|
+
export const DEFAULT_STATIC_GENERATION_RETRY_COUNT = 3;
|
|
38
|
+
|
|
39
|
+
function positiveIntegerFromEnvironment(name) {
|
|
40
|
+
const parsed = Number.parseInt(process.env[name] ?? "", 10);
|
|
41
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function staticGenerationSettings() {
|
|
45
|
+
return {
|
|
46
|
+
cpus: positiveIntegerFromEnvironment("PAPYRUS_STATIC_GENERATION_WORKERS") ?? DEFAULT_STATIC_GENERATION_WORKERS,
|
|
47
|
+
staticGenerationMaxConcurrency:
|
|
48
|
+
positiveIntegerFromEnvironment("PAPYRUS_STATIC_GENERATION_CONCURRENCY") ?? DEFAULT_STATIC_GENERATION_CONCURRENCY,
|
|
49
|
+
staticGenerationRetryCount: DEFAULT_STATIC_GENERATION_RETRY_COUNT,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const DEFAULT_TRANSPILE_PACKAGES = ["@anthusai/papyrus", "cyclotron"];
|
|
54
|
+
|
|
55
|
+
export function mergeTranspilePackages(existing = []) {
|
|
56
|
+
return [...new Set([...existing, ...DEFAULT_TRANSPILE_PACKAGES])];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export const RUNTIME_TRACED_FILES = ["./corpora/**/*", "./amplify_outputs.json"];
|
|
60
|
+
|
|
61
|
+
export function mergeOutputFileTracingIncludes(existing = {}) {
|
|
62
|
+
const merged = { ...existing };
|
|
63
|
+
const current = merged["/**"] ?? [];
|
|
64
|
+
merged["/**"] = [...new Set([...current, ...RUNTIME_TRACED_FILES])];
|
|
65
|
+
return merged;
|
|
66
|
+
}
|
|
67
|
+
|
|
25
68
|
const EMPTY_THEME = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../lib/empty-theme.css");
|
|
26
69
|
|
|
27
70
|
export function withPapyrus(nextConfig = {}, options = {}) {
|
|
@@ -38,11 +81,13 @@ export function withPapyrus(nextConfig = {}, options = {}) {
|
|
|
38
81
|
};
|
|
39
82
|
return {
|
|
40
83
|
distDir: process.env.NEXT_DIST_DIR || ".next",
|
|
84
|
+
expireTime: READER_EXPIRE_TIME_SECONDS,
|
|
41
85
|
...nextConfig,
|
|
42
|
-
transpilePackages:
|
|
86
|
+
transpilePackages: mergeTranspilePackages(nextConfig.transpilePackages),
|
|
43
87
|
serverExternalPackages: [...new Set([...(nextConfig.serverExternalPackages ?? []), ...SERVER_EXTERNAL])],
|
|
88
|
+
outputFileTracingIncludes: mergeOutputFileTracingIncludes(nextConfig.outputFileTracingIncludes),
|
|
44
89
|
images: nextConfig.images ?? { remotePatterns: [{ protocol: "https", hostname: "**" }] },
|
|
45
|
-
experimental: { devtoolSegmentExplorer: false, ...nextConfig.experimental },
|
|
90
|
+
experimental: { devtoolSegmentExplorer: false, ...staticGenerationSettings(), ...nextConfig.experimental },
|
|
46
91
|
turbopack: {
|
|
47
92
|
...nextConfig.turbopack,
|
|
48
93
|
resolveAlias: {
|