@anthusai/papyrus 0.0.0 → 1.0.0-next.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (254) hide show
  1. package/LICENSE +21 -0
  2. package/amplify/auth/resource.js +61 -0
  3. package/amplify/auth/resource.ts +65 -0
  4. package/amplify/data/resource.js +2037 -0
  5. package/amplify/data/resource.ts +2148 -0
  6. package/amplify/data/schema.js +1850 -0
  7. package/amplify/data/schema.ts +1953 -0
  8. package/amplify/functions/assignment-action/handler.ts +1416 -0
  9. package/amplify/functions/assignment-action/resource.js +8 -0
  10. package/amplify/functions/assignment-action/resource.ts +9 -0
  11. package/amplify/functions/category-action/handler.ts +2259 -0
  12. package/amplify/functions/category-action/resource.js +8 -0
  13. package/amplify/functions/category-action/resource.ts +9 -0
  14. package/amplify/functions/console-chat-responder/Cargo.lock +3456 -0
  15. package/amplify/functions/console-chat-responder/Cargo.toml +26 -0
  16. package/amplify/functions/console-chat-responder/Dockerfile +19 -0
  17. package/amplify/functions/console-chat-responder/py/execute_tactus_runner.py +116 -0
  18. package/amplify/functions/console-chat-responder/resource.js +153 -0
  19. package/amplify/functions/console-chat-responder/resource.ts +179 -0
  20. package/amplify/functions/console-chat-responder/src/main.rs +3242 -0
  21. package/amplify/functions/email-submission-processor/handler.py +46 -0
  22. package/amplify/functions/email-submission-processor/requirements.txt +2 -0
  23. package/amplify/functions/email-submission-processor/resource.js +56 -0
  24. package/amplify/functions/email-submission-processor/resource.ts +69 -0
  25. package/amplify/functions/graphql-jwt-authorizer/handler.ts +193 -0
  26. package/amplify/functions/graphql-jwt-authorizer/resource.js +14 -0
  27. package/amplify/functions/graphql-jwt-authorizer/resource.ts +15 -0
  28. package/amplify/functions/knowledge-query/handler.py +1 -0
  29. package/amplify/functions/knowledge-query/requirements.txt +3 -0
  30. package/amplify/functions/knowledge-query/resource.js +50 -0
  31. package/amplify/functions/knowledge-query/resource.ts +61 -0
  32. package/amplify/functions/manage-user-role/handler.ts +799 -0
  33. package/amplify/functions/manage-user-role/resource.js +8 -0
  34. package/amplify/functions/manage-user-role/resource.ts +9 -0
  35. package/amplify/functions/model-attachment-upload/handler.ts +387 -0
  36. package/amplify/functions/model-attachment-upload/resource.js +8 -0
  37. package/amplify/functions/model-attachment-upload/resource.ts +9 -0
  38. package/amplify/functions/newsroom-summary/handler.ts +321 -0
  39. package/amplify/functions/newsroom-summary/resource.js +8 -0
  40. package/amplify/functions/newsroom-summary/resource.ts +9 -0
  41. package/amplify/functions/procedure-action/handler.ts +621 -0
  42. package/amplify/functions/procedure-action/resource.js +8 -0
  43. package/amplify/functions/procedure-action/resource.ts +9 -0
  44. package/amplify/functions/reader-settings/handler.ts +322 -0
  45. package/amplify/functions/reader-settings/resource.js +8 -0
  46. package/amplify/functions/reader-settings/resource.ts +9 -0
  47. package/amplify/functions/ses-inbound-receive/handler.ts +493 -0
  48. package/amplify/functions/ses-inbound-receive/resource.js +8 -0
  49. package/amplify/functions/ses-inbound-receive/resource.ts +9 -0
  50. package/amplify/functions/shared/amplify-secrets.ts +65 -0
  51. package/amplify/functions/shared/console-chat-enqueue.ts +117 -0
  52. package/amplify/functions/shared/email-mime-intake.ts +196 -0
  53. package/amplify/functions/shared/email-submission.ts +415 -0
  54. package/amplify/functions/shared/inbound-email-intake.ts +37 -0
  55. package/amplify/functions/shared/lambda-data-client.ts +21 -0
  56. package/amplify/functions/shared/model-payloads.ts +186 -0
  57. package/amplify/functions/shared/python-bundle.js +115 -0
  58. package/amplify/functions/shared/python-bundle.ts +141 -0
  59. package/amplify/functions/shared/slack-events.ts +111 -0
  60. package/amplify/functions/slack-delivery/handler.py +112 -0
  61. package/amplify/functions/slack-delivery/requirements.txt +2 -0
  62. package/amplify/functions/slack-delivery/resource.js +38 -0
  63. package/amplify/functions/slack-delivery/resource.ts +51 -0
  64. package/amplify/functions/slack-events/handler.ts +155 -0
  65. package/amplify/functions/slack-events/resource.js +11 -0
  66. package/amplify/functions/slack-events/resource.ts +12 -0
  67. package/amplify/inbound-email/stack.js +46 -0
  68. package/amplify/inbound-email/stack.ts +61 -0
  69. package/amplify/package.json +3 -0
  70. package/amplify/site-backend-config.js +1 -0
  71. package/amplify/site-backend-config.ts +30 -0
  72. package/amplify/site-backend.js +587 -0
  73. package/amplify/site-backend.ts +704 -0
  74. package/amplify/storage/resource.js +18 -0
  75. package/amplify/storage/resource.ts +19 -0
  76. package/app/[year]/[month]/[day]/[articleSlug]/page.tsx +62 -0
  77. package/app/[year]/[month]/[day]/edition-route-page.tsx +53 -0
  78. package/app/[year]/[month]/[day]/page/[pageNumber]/page.tsx +32 -0
  79. package/app/[year]/[month]/[day]/page.tsx +22 -0
  80. package/app/[year]/[month]/[day]/section/[sectionKey]/page.tsx +32 -0
  81. package/app/api/archive/editions/route.ts +18 -0
  82. package/app/api/media/[...path]/route.ts +35 -0
  83. package/app/api/revalidate/route.ts +94 -0
  84. package/app/archive/page.tsx +24 -0
  85. package/app/articles/[slug]/page.tsx +35 -0
  86. package/app/globals.css +10329 -0
  87. package/app/layout.tsx +146 -0
  88. package/app/newsroom/[section]/[...selection]/page.tsx +50 -0
  89. package/app/newsroom/[section]/page.tsx +47 -0
  90. package/app/newsroom/forum/[threadId]/page.tsx +35 -0
  91. package/app/newsroom/insights/[threadId]/page.tsx +22 -0
  92. package/app/newsroom/insights/page.tsx +14 -0
  93. package/app/newsroom/layout.tsx +12 -0
  94. package/app/newsroom/page.tsx +31 -0
  95. package/app/newsroom/sections/[sectionId]/page.tsx +17 -0
  96. package/app/page.tsx +272 -0
  97. package/app/settings/page.tsx +14 -0
  98. package/app/tailwind.css +65 -0
  99. package/bin/papyrus-app.mjs +10 -0
  100. package/bin/papyrus-infra.mjs +39 -0
  101. package/components/ai-elements/conversation.tsx +168 -0
  102. package/components/ai-elements/message.tsx +360 -0
  103. package/components/ai-elements/model-selector.tsx +30 -0
  104. package/components/ai-elements/prompt-input.tsx +1461 -0
  105. package/components/ai-elements/shimmer.tsx +76 -0
  106. package/components/ai-elements/suggestion.tsx +54 -0
  107. package/components/ai-elements/tool.tsx +173 -0
  108. package/components/amplify-client-provider.tsx +140 -0
  109. package/components/archive-grid.tsx +89 -0
  110. package/components/archive-shell.tsx +41 -0
  111. package/components/article-video.tsx +47 -0
  112. package/components/blog-page-background.tsx +20 -0
  113. package/components/dev-sandbox-editor-sign-in.tsx +60 -0
  114. package/components/news-desk-client-provider.tsx +211 -0
  115. package/components/news-desk-page.tsx +119 -0
  116. package/components/news-desk-taxonomy-client.ts +3684 -0
  117. package/components/newspaper.tsx +1929 -0
  118. package/components/newsroom-assignments-view.tsx +664 -0
  119. package/components/newsroom-ops-overview.tsx +226 -0
  120. package/components/newsroom-ops-shell.tsx +319 -0
  121. package/components/newsroom-references-view.tsx +598 -0
  122. package/components/newsroom-topics-view.tsx +425 -0
  123. package/components/papyrus-console-shell.tsx +1912 -0
  124. package/components/pictogram-figure.tsx +65 -0
  125. package/components/presentation-footer.tsx +146 -0
  126. package/components/reader-auth-control.tsx +162 -0
  127. package/components/reader-auth-state.ts +122 -0
  128. package/components/reader-settings.ts +332 -0
  129. package/components/reader-theme-control.tsx +85 -0
  130. package/components/reference-source-preview.tsx +163 -0
  131. package/components/settings-page.tsx +239 -0
  132. package/components/topic-steering-workspace.tsx +18063 -0
  133. package/components/ui/badge.tsx +30 -0
  134. package/components/ui/button-group.tsx +87 -0
  135. package/components/ui/button.tsx +58 -0
  136. package/components/ui/card.tsx +32 -0
  137. package/components/ui/command.tsx +194 -0
  138. package/components/ui/dialog.tsx +158 -0
  139. package/components/ui/dropdown-menu.tsx +266 -0
  140. package/components/ui/hover-card.tsx +51 -0
  141. package/components/ui/input-group.tsx +158 -0
  142. package/components/ui/input.tsx +20 -0
  143. package/components/ui/scroll-area.tsx +16 -0
  144. package/components/ui/select.tsx +199 -0
  145. package/components/ui/separator.tsx +23 -0
  146. package/components/ui/sheet.tsx +92 -0
  147. package/components/ui/spinner.tsx +10 -0
  148. package/components/ui/tabs.tsx +113 -0
  149. package/components/ui/textarea.tsx +18 -0
  150. package/components/ui/tooltip.tsx +66 -0
  151. package/components/use-resolved-papyrus-theme.ts +47 -0
  152. package/infra/amplify-app-shell.js +109 -0
  153. package/infra/amplify-app-shell.ts +155 -0
  154. package/infra/index.js +12 -0
  155. package/lib/amplify-outputs-guard.ts +24 -0
  156. package/lib/amplify-outputs-path.ts +16 -0
  157. package/lib/amplify-server-runtime.ts +63 -0
  158. package/lib/archive-data.ts +30 -0
  159. package/lib/archive-types.ts +15 -0
  160. package/lib/articles.ts +320 -0
  161. package/lib/cached-content-repository.ts +89 -0
  162. package/lib/category-dashboard.ts +37 -0
  163. package/lib/category-repository.ts +1907 -0
  164. package/lib/console-chat-client.ts +1316 -0
  165. package/lib/console-web-context.ts +118 -0
  166. package/lib/content-load-timing.ts +23 -0
  167. package/lib/content-repository.ts +40 -0
  168. package/lib/content-types.ts +104 -0
  169. package/lib/define-site.js +3 -0
  170. package/lib/define-site.ts +21 -0
  171. package/lib/demo-amplify-outputs.ts +15 -0
  172. package/lib/dev-sandbox-editor-auth.ts +18 -0
  173. package/lib/doctrine.ts +128 -0
  174. package/lib/edition-routes.ts +155 -0
  175. package/lib/edition-sections.ts +111 -0
  176. package/lib/empty-edition-layout-plan.ts +109 -0
  177. package/lib/excerpts.ts +8 -0
  178. package/lib/graphql-content-repository.ts +986 -0
  179. package/lib/image-url.ts +10 -0
  180. package/lib/layout-plan.ts +981 -0
  181. package/lib/layout-scenarios.ts +564 -0
  182. package/lib/markus-body.ts +168 -0
  183. package/lib/markus-ir.ts +235 -0
  184. package/lib/markus-projection.ts +243 -0
  185. package/lib/markus-to-article.ts +93 -0
  186. package/lib/news-desk-session.ts +160 -0
  187. package/lib/newspaper-layout.ts +3459 -0
  188. package/lib/newsroom-assignments.ts +173 -0
  189. package/lib/newsroom-base-path.ts +48 -0
  190. package/lib/newsroom-card-layout.ts +102 -0
  191. package/lib/newsroom-category-drilldown.ts +133 -0
  192. package/lib/newsroom-demo-dashboard.ts +267 -0
  193. package/lib/newsroom-demo-profile.ts +46 -0
  194. package/lib/newsroom-forum-routes.ts +153 -0
  195. package/lib/newsroom-index-filters.ts +202 -0
  196. package/lib/newsroom-knowledge-query-request.ts +51 -0
  197. package/lib/newsroom-list-selection.ts +42 -0
  198. package/lib/newsroom-nav.ts +42 -0
  199. package/lib/newsroom-references.ts +116 -0
  200. package/lib/newsroom-sections.ts +52 -0
  201. package/lib/newsroom-topics.ts +118 -0
  202. package/lib/papyrus-object-kinds.ts +24 -0
  203. package/lib/papyrus-web-locations.ts +480 -0
  204. package/lib/pilobol-sample.ts +167 -0
  205. package/lib/presentation-footer.ts +92 -0
  206. package/lib/pretext-layout.ts +179 -0
  207. package/lib/public-placeholder-config.ts +102 -0
  208. package/lib/publication-items.ts +181 -0
  209. package/lib/reader-route-config.ts +1 -0
  210. package/lib/reader-static-params.ts +56 -0
  211. package/lib/reader-storage-url.ts +63 -0
  212. package/lib/reference-display.ts +74 -0
  213. package/lib/reference-policy.ts +97 -0
  214. package/lib/reference-source-preview.ts +175 -0
  215. package/lib/renderer-config.ts +50 -0
  216. package/lib/renderer.ts +87 -0
  217. package/lib/reporting-story-budget.ts +638 -0
  218. package/lib/semantic-graph.ts +554 -0
  219. package/lib/site-brand-tenant.ts +41 -0
  220. package/lib/site-brand.ts +179 -0
  221. package/lib/site-renderer.ts +17 -0
  222. package/lib/site-stack.ts +195 -0
  223. package/lib/themed-image.ts +30 -0
  224. package/lib/utils.ts +6 -0
  225. package/middleware.ts +78 -0
  226. package/package.json +296 -1
  227. package/publications/anth_us/brand.ts +68 -0
  228. package/publications/anth_us/theme.css +66 -0
  229. package/publications/papyrus/theme.css +11 -0
  230. package/publications/pilobol_us/brand.ts +37 -0
  231. package/publications/pilobol_us/theme.css +140 -0
  232. package/publications/threat_intelligence/blog-defense/graph.ts +636 -0
  233. package/publications/threat_intelligence/blog-defense/layout.ts +934 -0
  234. package/publications/threat_intelligence/blog-defense/page-background.tsx +590 -0
  235. package/publications/threat_intelligence/brand.ts +40 -0
  236. package/publications/threat_intelligence/pictograms/art.tsx +608 -0
  237. package/publications/threat_intelligence/pictograms/figure.tsx +82 -0
  238. package/publications/threat_intelligence/pictograms/registry.ts +30 -0
  239. package/publications/threat_intelligence/pictograms/system.tsx +305 -0
  240. package/publications/threat_intelligence/seed/seed-edition-content.json +629 -0
  241. package/publications/threat_intelligence/theme.css +1440 -0
  242. package/renderers/markus/index.ts +25 -0
  243. package/renderers/markus/stubs.tsx +33 -0
  244. package/renderers/pretext/article-page.tsx +174 -0
  245. package/renderers/pretext/index.ts +30 -0
  246. package/renderers/pretext/layouts.ts +16 -0
  247. package/renderers/pretext/presentation-shell.tsx +477 -0
  248. package/routes.manifest.json +182 -0
  249. package/scripts/fixtures/pilobol-sample.ast.json +234 -0
  250. package/src/backend.js +1 -0
  251. package/src/backend.ts +3 -0
  252. package/src/sync.mjs +87 -0
  253. package/src/with-papyrus.d.mts +2 -0
  254. package/src/with-papyrus.mjs +47 -0
@@ -0,0 +1,25 @@
1
+ import type { EditionPresentationFormat } from "../../lib/content-types";
2
+ import type { Renderer } from "../../lib/renderer";
3
+ import { MarkusArticleStub, MarkusEditionStub, MarkusItemStub } from "./stubs";
4
+
5
+ /** CSS paths relative to the static site root (`web/dist/`). */
6
+ export const MARKUS_STYLESHEETS = ["css/markus-vendor.css", "css/site-theme.css"] as const;
7
+
8
+ export function markusSupportsLayout(_layout: EditionPresentationFormat): boolean {
9
+ return false;
10
+ }
11
+
12
+ /**
13
+ * Markus renderer: Python build emits static HTML under `web/dist/`.
14
+ * Preview with `python -m http.server` on that folder — no Next.js shell.
15
+ */
16
+ export const markusRenderer: Renderer = {
17
+ id: "markus",
18
+ renderEdition: MarkusEditionStub,
19
+ renderArticle: MarkusArticleStub,
20
+ renderItem: MarkusItemStub,
21
+ stylesheets: () => [...MARKUS_STYLESHEETS],
22
+ supportsLayout: markusSupportsLayout,
23
+ };
24
+
25
+ export { MarkusArticleStub, MarkusEditionStub, MarkusItemStub } from "./stubs";
@@ -0,0 +1,33 @@
1
+ "use client";
2
+
3
+ import type { RenderArticleProps, RenderEditionProps, RenderItemProps } from "../../lib/renderer";
4
+
5
+ /**
6
+ * Markus renders exclusively via the Python static build
7
+ * (`poetry run papyrus renderers markus-build` → `web/dist/`).
8
+ * These components satisfy the Renderer interface but are not wired into
9
+ * `app/*` routes and must not become a second render path.
10
+ */
11
+ function StaticRendererNotice({ label }: { label: string }) {
12
+ return (
13
+ <main className="markus-static-notice">
14
+ <p>
15
+ <strong>{label}</strong> uses the Markus static build output only. Run{" "}
16
+ <code>poetry run papyrus renderers markus-build</code>, then preview{" "}
17
+ <code>web/dist/</code> with a plain static file server — not Next.js.
18
+ </p>
19
+ </main>
20
+ );
21
+ }
22
+
23
+ export function MarkusEditionStub(_props: RenderEditionProps) {
24
+ return <StaticRendererNotice label="Edition view" />;
25
+ }
26
+
27
+ export function MarkusArticleStub(_props: RenderArticleProps) {
28
+ return <StaticRendererNotice label="Article view" />;
29
+ }
30
+
31
+ export function MarkusItemStub(_props: RenderItemProps) {
32
+ return <StaticRendererNotice label="Item view" />;
33
+ }
@@ -0,0 +1,174 @@
1
+ "use client";
2
+
3
+ import Link from "next/link";
4
+ import type { Article } from "../../lib/articles";
5
+ import type { PublicationItem } from "../../lib/publication-items";
6
+ import { getPublicationItemVideoAsset } from "../../lib/publication-items";
7
+ import type { ArticlePageEditionFooter, RenderArticleProps, RenderItemProps } from "../../lib/renderer";
8
+ import { SITE_BRAND } from "../../lib/site-brand";
9
+ import { ArticleVideoFigure } from "../../components/article-video";
10
+ import { PictogramFigure as ThreatIntelligencePictogramFigure } from "../../publications/threat_intelligence/pictograms/figure";
11
+ import { PictogramFigure as GenericPictogramFigure } from "../../components/pictogram-figure";
12
+ import { PresentationFooter } from "../../components/presentation-footer";
13
+
14
+ // Threat Intelligence supplies its own pictogram figure media; any other
15
+ // publication gets the generic fallback (components/pictogram-figure.tsx).
16
+ // Same decoupling as renderers/pretext/presentation-shell.tsx -- see
17
+ // docs/pluggable-publishers.md section 2.6 and PPY-d79ff2.
18
+ const PictogramFigure = SITE_BRAND.id === "threat-intelligence" ? ThreatIntelligencePictogramFigure : GenericPictogramFigure;
19
+
20
+ export type { ArticlePageEditionFooter };
21
+
22
+ type ArticlePageViewProps = RenderArticleProps;
23
+
24
+ export function ArticlePageView({ article, backHref, backLabel = SITE_BRAND.backToHomeLabel, editionFooter, editionDate }: ArticlePageViewProps) {
25
+ const articleDate = editionDate ? formatArticleDate(editionDate) : null;
26
+
27
+ return (
28
+ <main className={getArticleShellClassName(editionFooter)}>
29
+ <nav className="article-nav">
30
+ <Link href={backHref}>{backLabel}</Link>
31
+ <span>{article.section}</span>
32
+ </nav>
33
+ <article className="article-page">
34
+ {article.video ? (
35
+ <div className="article-page__hero-video">
36
+ <ArticleVideoFigure slug={article.slug} video={article.video} />
37
+ </div>
38
+ ) : null}
39
+ <header>
40
+ <p className="story-label">{article.section}</p>
41
+ <h1>{article.headline}</h1>
42
+ <p className="article-deck">{article.deck}</p>
43
+ <div className="story-byline">
44
+ <span>{article.byline}</span>
45
+ <span>{article.dateline}</span>
46
+ {articleDate ? <time dateTime={editionDate}>{articleDate}</time> : null}
47
+ </div>
48
+ </header>
49
+ <div className="article-body">
50
+ <ArticleLeadPictogram article={article} />
51
+ {article.body.map((paragraph) => (
52
+ <p key={paragraph}>{paragraph}</p>
53
+ ))}
54
+ </div>
55
+ </article>
56
+ {editionFooter ? <ArticleEditionFooter footer={editionFooter} /> : null}
57
+ </main>
58
+ );
59
+ }
60
+
61
+ type ItemPageViewProps = RenderItemProps;
62
+
63
+ export function ItemPageView({ item, backHref, backLabel = "Back to edition", editionFooter, editionDate }: ItemPageViewProps) {
64
+ if (item.type === "article") {
65
+ return <ArticlePageView article={item} backHref={backHref} backLabel={backLabel} editionFooter={editionFooter} editionDate={editionDate} />;
66
+ }
67
+
68
+ const itemDate = editionDate ? formatArticleDate(editionDate) : null;
69
+ const itemVideo = getPublicationItemVideoAsset(item);
70
+
71
+ return (
72
+ <main className={getArticleShellClassName(editionFooter)}>
73
+ <nav className="article-nav">
74
+ <Link href={backHref}>{backLabel}</Link>
75
+ <span>{item.section ?? item.type}</span>
76
+ </nav>
77
+ <article className="article-page" data-item-type={item.type}>
78
+ {itemVideo ? (
79
+ <div className="article-page__hero-video">
80
+ <ArticleVideoFigure slug={item.slug} video={itemVideo} />
81
+ </div>
82
+ ) : null}
83
+ <header>
84
+ <p className="story-label">{item.section ?? item.type}</p>
85
+ <h1>{item.title}</h1>
86
+ {item.deck ? <p className="article-deck">{item.deck}</p> : null}
87
+ {itemDate ? (
88
+ <div className="story-byline">
89
+ <time dateTime={editionDate}>{itemDate}</time>
90
+ </div>
91
+ ) : null}
92
+ </header>
93
+ <div className="article-body">
94
+ <ItemLeadPictogram item={item} />
95
+ {(item.body ?? []).map((paragraph) => (
96
+ <p key={paragraph}>{paragraph}</p>
97
+ ))}
98
+ </div>
99
+ </article>
100
+ {editionFooter ? <ArticleEditionFooter footer={editionFooter} /> : null}
101
+ </main>
102
+ );
103
+ }
104
+
105
+ function ArticleLeadPictogram({ article }: { article: Article }) {
106
+ if (!article.image) return null;
107
+ return (
108
+ <PictogramFigure
109
+ alt={article.image.alt}
110
+ caption={article.image.caption}
111
+ credit={article.image.credit}
112
+ figureClassName="article-photo"
113
+ height={680}
114
+ layout={article.image.layout}
115
+ priority
116
+ sizes="(max-width: 980px) 100vw, 900px"
117
+ slug={article.slug}
118
+ src={article.image.src}
119
+ themeVariants={article.image.themeVariants}
120
+ width={1200}
121
+ />
122
+ );
123
+ }
124
+
125
+ function ItemLeadPictogram({ item }: { item: PublicationItem }) {
126
+ const image = item.type === "article" ? item.image : item.image;
127
+ if (!image) return null;
128
+ return (
129
+ <PictogramFigure
130
+ alt={image.alt}
131
+ caption={image.caption}
132
+ credit={image.credit}
133
+ figureClassName="article-photo"
134
+ height={680}
135
+ layout={image.layout}
136
+ priority
137
+ sizes="(max-width: 980px) 100vw, 900px"
138
+ slug={item.slug}
139
+ src={image.src}
140
+ themeVariants={image.themeVariants}
141
+ width={1200}
142
+ />
143
+ );
144
+ }
145
+
146
+ function ArticleEditionFooter({ footer }: { footer: ArticlePageEditionFooter }) {
147
+ return (
148
+ <PresentationFooter
149
+ editionBasePath={footer.editionBasePath}
150
+ entries={footer.entries}
151
+ resolveSectionHref={(entry) => `${footer.editionBasePath}#section-${entry.sectionKey}`}
152
+ subtitle={footer.subtitle}
153
+ title={footer.title}
154
+ />
155
+ );
156
+ }
157
+
158
+ function getArticleShellClassName(editionFooter: ArticlePageEditionFooter | undefined): string {
159
+ return editionFooter ? "article-shell article-shell--edition" : "article-shell";
160
+ }
161
+
162
+ function formatArticleDate(value: string): string {
163
+ const normalized = value.trim();
164
+ if (!normalized) return value;
165
+
166
+ const date = new Date(`${normalized}T00:00:00`);
167
+ if (Number.isNaN(date.getTime())) return value;
168
+
169
+ return new Intl.DateTimeFormat("en-US", {
170
+ day: "numeric",
171
+ month: "long",
172
+ year: "numeric",
173
+ }).format(date);
174
+ }
@@ -0,0 +1,30 @@
1
+ import type { Renderer } from "../../lib/renderer";
2
+ import { PRETEXT_LAYOUTS, pretextSupportsLayout } from "./layouts";
3
+ import { ArticlePageView, ItemPageView } from "./article-page";
4
+ import { PresentationShell } from "./presentation-shell";
5
+
6
+ export { ArticlePageView, ItemPageView } from "./article-page";
7
+ export { PresentationShell } from "./presentation-shell";
8
+ export type { PresentationTarget } from "./presentation-shell";
9
+ export { PRETEXT_LAYOUTS, pretextSupportsLayout } from "./layouts";
10
+
11
+ /**
12
+ * The Pretext renderer: the existing client-side layout solver
13
+ * (`@chenglou/pretext` + `components/newspaper.tsx` +
14
+ * `renderers/pretext/presentation-shell.tsx`), retrofitted onto the
15
+ * `Renderer` interface (lib/renderer.ts). This is a pure retrofit -- no
16
+ * rendering behavior changed, only how the existing implementation is
17
+ * exposed.
18
+ */
19
+ export const pretextRenderer: Renderer = {
20
+ id: "pretext",
21
+ renderEdition: PresentationShell,
22
+ renderArticle: ArticlePageView,
23
+ renderItem: ItemPageView,
24
+ // Pretext's CSS is not extracted from the monolithic app/globals.css
25
+ // bundle imported unconditionally by app/layout.tsx, so there is nothing
26
+ // additional for this renderer to declare today. See lib/renderer.ts's
27
+ // `stylesheets` doc comment.
28
+ stylesheets: () => [],
29
+ supportsLayout: pretextSupportsLayout,
30
+ };
@@ -0,0 +1,16 @@
1
+ import type { PretextLayout } from "../../lib/renderer-config";
2
+
3
+ /**
4
+ * Layout ("newsprint" | "blog" | "magazine") is Pretext-internal: it is the
5
+ * look within Pretext, not a concept every renderer needs to share. This is
6
+ * the canonical list of layouts the Pretext renderer actually supports,
7
+ * consumed both by `renderers/pretext`'s `supportsLayout` and by
8
+ * `lib/site-brand.ts`'s `getPresentationChoices` (today the only renderer,
9
+ * so "layouts the app can choose from" and "layouts Pretext supports" are
10
+ * the same list).
11
+ */
12
+ export const PRETEXT_LAYOUTS: readonly PretextLayout[] = ["newsprint", "blog", "magazine"];
13
+
14
+ export function pretextSupportsLayout(layout: PretextLayout): boolean {
15
+ return PRETEXT_LAYOUTS.includes(layout);
16
+ }