@anthusai/papyrus 1.4.0-next.1 → 1.4.0-next.10
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/data/resource.js +134 -3
- package/amplify/data/resource.ts +145 -3
- package/amplify/data/schema.js +131 -0
- package/amplify/data/schema.ts +142 -0
- package/amplify/functions/category-action/handler.ts +272 -20
- package/amplify/functions/console-chat-responder/src/main.rs +1 -1
- package/amplify/functions/content-actions/handler.py +23 -0
- package/amplify/functions/content-actions/requirements.txt +1 -1
- package/amplify/functions/content-actions/resource.js +1 -1
- package/amplify/functions/content-actions/resource.ts +1 -1
- package/amplify/functions/renditions/requirements.txt +1 -1
- package/amplify/functions/shared/curation-delegation-flow.ts +147 -0
- package/amplify/functions/shared/curation-delegation.ts +115 -0
- package/amplify/functions/shared/python-bundle.js +3 -3
- package/amplify/functions/shared/python-bundle.ts +3 -3
- package/amplify/functions/shared/reference-curation-metadata.ts +51 -0
- package/amplify/functions/shared/slack-events.ts +2 -2
- package/amplify/publication/renditions-function.js +1 -1
- package/amplify/publication/renditions-function.ts +1 -1
- package/app/[year]/[month]/[day]/[articleSlug]/page.tsx +2 -1
- package/app/[year]/[month]/[day]/edition-route-page.tsx +2 -1
- package/app/[year]/[month]/[day]/page/[pageNumber]/page.tsx +2 -1
- package/app/[year]/[month]/[day]/page.tsx +3 -0
- package/app/[year]/[month]/[day]/section/[sectionKey]/page.tsx +2 -0
- package/app/api/archive/editions/route.ts +2 -0
- package/app/api/auth/prospectus/accounts/route.ts +9 -0
- package/app/api/local-preview/derive/route.ts +28 -0
- package/app/api/local-preview/media/route.ts +25 -0
- package/app/archive/page.tsx +3 -0
- package/app/globals.css +28 -28
- package/app/layout.tsx +8 -5
- package/app/newsroom/[section]/[...selection]/page.tsx +0 -1
- package/app/newsroom/[section]/page.tsx +3 -2
- package/app/newsroom/articles/page.tsx +8 -1
- package/app/newsroom/insights/[threadId]/page.tsx +5 -16
- package/app/newsroom/insights/page.tsx +4 -12
- package/app/newsroom/sections/[sectionId]/page.tsx +3 -0
- package/app/page.tsx +30 -1
- package/components/administration-delegations-panel.tsx +156 -0
- package/components/curation-delegation-client.ts +104 -0
- package/components/item-stream-view.tsx +63 -0
- package/components/markus-ir-preview.tsx +47 -2
- package/components/news-desk-page.tsx +0 -1
- package/components/news-desk-taxonomy-client.ts +82 -242
- package/components/newsroom-article-editor.tsx +138 -40
- package/components/newsroom-assignment-detail.tsx +79 -0
- package/components/newsroom-assignments-view.tsx +1 -1
- package/components/newsroom-board-view.tsx +128 -51
- package/components/newsroom-newsprint-board.css +5 -46
- package/components/newsroom-ops-overview.tsx +27 -5
- package/components/newsroom-organizer-shell.tsx +26 -8
- package/components/newsroom-organizer.css +267 -12
- package/components/newsroom-references-view.tsx +100 -23
- package/components/newsroom-topics-view.tsx +1 -1
- package/components/priming-proof-page.tsx +17 -8
- package/components/prospectus-account-chooser.tsx +131 -0
- package/components/reference-cyclotron-status.tsx +5 -5
- package/components/reference-cyclotron-suggestion.tsx +143 -0
- package/components/reference-live-agreement.tsx +62 -0
- package/components/reference-section-suggestion.tsx +104 -0
- package/components/story-reporting-trail-client.ts +91 -0
- package/components/story-reporting-trail.tsx +115 -0
- package/components/topic-steering-workspace.tsx +245 -678
- package/components/ui/sheet.tsx +10 -4
- package/components/use-paged-content-item-versions.ts +151 -0
- package/components/wiki-concepts-view.tsx +153 -0
- package/components/wiki-index-client.ts +51 -0
- package/infra/amplify-app-shell.js +17 -3
- package/infra/amplify-app-shell.ts +18 -3
- package/infra/site-config.js +6 -1
- package/infra/site-config.ts +7 -1
- package/lib/approved-priming-proof-reports.ts +6 -3
- package/lib/approved-priming-proofs/papyrus.json +90 -0
- package/lib/blog-feature-solver.ts +1 -109
- package/lib/category-repository.ts +1 -1
- package/lib/content-actions-client.ts +3 -0
- package/lib/content-actions-demo.ts +55 -0
- package/lib/content-item-lifecycle.ts +34 -5
- package/lib/content-source-context.ts +9 -1
- package/lib/curation-delegation-helpers.ts +69 -0
- package/lib/cyclotron-suggestions.ts +263 -0
- package/lib/front-matter-fields.ts +42 -0
- package/lib/front-mosaic.ts +2 -1
- package/lib/graphql-content-repository.ts +42 -7
- package/lib/item-stream.ts +47 -0
- package/lib/layout-plan.ts +3 -2
- package/lib/layout-warnings.ts +8 -0
- package/lib/local-preview-section-fixtures.ts +72 -0
- package/lib/local-preview-seed.ts +196 -7
- package/lib/local-preview-tenant.ts +27 -0
- package/lib/newsroom-articles.ts +2 -0
- package/lib/newsroom-assignments.ts +14 -1
- package/lib/newsroom-board.ts +52 -7
- package/lib/newsroom-demo-dashboard.ts +1 -1
- package/lib/newsroom-forum-routes.ts +2 -43
- package/lib/newsroom-index-filters.ts +3 -40
- package/lib/newsroom-media-backend.ts +5 -0
- package/lib/newsroom-nav.ts +1 -3
- package/lib/newsroom-organizer-nav.ts +8 -14
- package/lib/newsroom-section-routing.ts +1 -1
- package/lib/newsroom-sections.ts +12 -0
- package/lib/papyrus-web-locations.ts +3 -24
- package/lib/priming-proof-report.ts +1 -0
- package/lib/prospectus-account-client.ts +90 -0
- package/lib/prospectus-sign-in-routes.ts +45 -0
- package/lib/prospectus-site-identity.ts +13 -1
- package/lib/prospectus-tenant.ts +22 -0
- package/lib/reader-static-params.ts +2 -1
- package/lib/relevance-decisions.ts +29 -0
- package/lib/reporting-story-budget.ts +2 -2
- package/lib/semantic-graph.ts +5 -5
- package/lib/site-brand.ts +20 -0
- package/lib/site-env.ts +5 -0
- package/lib/site-section-suggestions.ts +120 -0
- package/lib/site-stack.ts +1 -1
- package/lib/story-reporting-trail.ts +106 -0
- package/lib/tenant-keys.ts +32 -0
- package/lib/wiki.ts +56 -0
- package/package.json +34 -2
- package/renderers/pretext/rhythm-article-page.tsx +1 -18
- package/routes.manifest.json +34 -7
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { createHash, randomBytes, randomInt } from "node:crypto"
|
|
2
|
+
|
|
3
|
+
export const CURATION_DELEGATION_PAYLOAD_KIND = "curation-delegation"
|
|
4
|
+
export const CURATION_DELEGATION_OWNER_TYPE = "curationDelegation"
|
|
5
|
+
export const DEFAULT_DELEGATION_HOURS = 8
|
|
6
|
+
export const MAXIMUM_DELEGATION_HOURS = 72
|
|
7
|
+
|
|
8
|
+
export type CurationDelegation = {
|
|
9
|
+
delegationId: string
|
|
10
|
+
tokenHash: string
|
|
11
|
+
grantorSub: string
|
|
12
|
+
grantorLabel: string
|
|
13
|
+
agentLabel: string
|
|
14
|
+
createdAt: string
|
|
15
|
+
expiresAt: string
|
|
16
|
+
revokedAt: string | null
|
|
17
|
+
userCode?: string | null
|
|
18
|
+
requestedHours?: number | null
|
|
19
|
+
pendingExpiresAt?: string | null
|
|
20
|
+
approvedAt?: string | null
|
|
21
|
+
deniedAt?: string | null
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type DelegationState = "pending" | "approved" | "denied" | "expired" | "revoked"
|
|
25
|
+
|
|
26
|
+
export type DelegationVerdict =
|
|
27
|
+
| { ok: true }
|
|
28
|
+
| { ok: false; reason: "unknown-token" | "wrong-agent" | "revoked" | "not-approved" | "expired" }
|
|
29
|
+
|
|
30
|
+
export function hashDelegationToken(token: string): string {
|
|
31
|
+
return createHash("sha256").update(token, "utf8").digest("hex")
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function newDelegationToken(delegationId: string): { token: string; tokenHash: string } {
|
|
35
|
+
const token = `${delegationId}~${randomBytes(24).toString("base64url")}`
|
|
36
|
+
return { token, tokenHash: hashDelegationToken(token) }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function delegationIdFromToken(token: string): string | null {
|
|
40
|
+
const separator = token.indexOf("~")
|
|
41
|
+
return separator > 0 ? token.slice(0, separator) : null
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function delegationExpiry(now: string, hours: number | null | undefined): string {
|
|
45
|
+
const requested = hours ?? DEFAULT_DELEGATION_HOURS
|
|
46
|
+
if (!Number.isFinite(requested) || requested <= 0 || requested > MAXIMUM_DELEGATION_HOURS) {
|
|
47
|
+
throw new Error(`A delegation lasts between 1 and ${MAXIMUM_DELEGATION_HOURS} hours.`)
|
|
48
|
+
}
|
|
49
|
+
return new Date(Date.parse(now) + requested * 3_600_000).toISOString()
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function delegationVerdict(
|
|
53
|
+
delegation: CurationDelegation | null,
|
|
54
|
+
presented: { token: string; agentLabel: string; now: string },
|
|
55
|
+
): DelegationVerdict {
|
|
56
|
+
if (!delegation || delegation.tokenHash !== hashDelegationToken(presented.token)) {
|
|
57
|
+
return { ok: false, reason: "unknown-token" }
|
|
58
|
+
}
|
|
59
|
+
if (delegation.agentLabel.trim().toLowerCase() !== presented.agentLabel.trim().toLowerCase()) {
|
|
60
|
+
return { ok: false, reason: "wrong-agent" }
|
|
61
|
+
}
|
|
62
|
+
if (delegation.revokedAt) return { ok: false, reason: "revoked" }
|
|
63
|
+
const state = delegationState(delegation, presented.now)
|
|
64
|
+
if (state === "pending" || state === "denied" || (state === "expired" && delegation.userCode && !delegation.approvedAt)) {
|
|
65
|
+
return { ok: false, reason: "not-approved" }
|
|
66
|
+
}
|
|
67
|
+
if (Date.parse(delegation.expiresAt) <= Date.parse(presented.now)) return { ok: false, reason: "expired" }
|
|
68
|
+
return { ok: true }
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function delegationRefusalMessage(reason: Exclude<DelegationVerdict, { ok: true }>["reason"]): string {
|
|
72
|
+
return {
|
|
73
|
+
"unknown-token": "That delegation token is not recognized.",
|
|
74
|
+
"wrong-agent": "That delegation was granted to a different agent.",
|
|
75
|
+
"revoked": "That delegation was revoked.",
|
|
76
|
+
"not-approved": "That delegation has not been approved by a person. Ask them to approve the code in the Newsroom.",
|
|
77
|
+
"expired": "That delegation has expired. Ask the person for a new one.",
|
|
78
|
+
}[reason]
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export const PENDING_DELEGATION_MINUTES = 10
|
|
82
|
+
export const MAXIMUM_PENDING_DELEGATION_REQUESTS = 5
|
|
83
|
+
export const PENDING_REQUEST_GRANTOR_SUB = "pending-device-authorization"
|
|
84
|
+
export const EXPIRED_REQUEST_GRANTOR_SUB = "expired-device-authorization"
|
|
85
|
+
export const USER_CODE_ALPHABET = "ABCDEFGHJKMNPQRSTUVWXYZ23456789"
|
|
86
|
+
export const USER_CODE_LENGTH = 8
|
|
87
|
+
|
|
88
|
+
export function newUserCode(): string {
|
|
89
|
+
let code = ""
|
|
90
|
+
for (let position = 0; position < USER_CODE_LENGTH; position += 1) {
|
|
91
|
+
code += USER_CODE_ALPHABET[randomInt(USER_CODE_ALPHABET.length)]
|
|
92
|
+
}
|
|
93
|
+
return code
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function formatUserCode(code: string): string {
|
|
97
|
+
return `${code.slice(0, 4)}-${code.slice(4)}`
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function normalizeUserCode(typed: string | null | undefined): string | null {
|
|
101
|
+
const stripped = (typed ?? "").toUpperCase().replace(/[\s-]/g, "")
|
|
102
|
+
if (stripped.length !== USER_CODE_LENGTH) return null
|
|
103
|
+
for (const character of stripped) if (!USER_CODE_ALPHABET.includes(character)) return null
|
|
104
|
+
return stripped
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function delegationState(delegation: CurationDelegation, now: string): DelegationState {
|
|
108
|
+
if (delegation.revokedAt) return "revoked"
|
|
109
|
+
if (delegation.deniedAt) return "denied"
|
|
110
|
+
if (delegation.userCode && !delegation.approvedAt) {
|
|
111
|
+
const pendingEnd = delegation.pendingExpiresAt ?? delegation.expiresAt
|
|
112
|
+
return Date.parse(pendingEnd) <= Date.parse(now) ? "expired" : "pending"
|
|
113
|
+
}
|
|
114
|
+
return Date.parse(delegation.expiresAt) <= Date.parse(now) ? "expired" : "approved"
|
|
115
|
+
}
|
|
@@ -126,9 +126,9 @@ function bundleFromPip(outputDir, options) {
|
|
|
126
126
|
}
|
|
127
127
|
export function bundleFromCheckout(outputDir, options) {
|
|
128
128
|
fs.copyFileSync(path.join(packageRoot, "amplify/functions", options.functionDir, "handler.py"), path.join(outputDir, "handler.py"));
|
|
129
|
-
for (const
|
|
130
|
-
fs.mkdirSync(path.join(outputDir,
|
|
131
|
-
fs.cpSync(path.join(packageRoot, "src",
|
|
129
|
+
for (const moduleName of options.modules) {
|
|
130
|
+
fs.mkdirSync(path.join(outputDir, moduleName), { recursive: true });
|
|
131
|
+
fs.cpSync(path.join(packageRoot, "src", moduleName), path.join(outputDir, moduleName), { recursive: true });
|
|
132
132
|
}
|
|
133
133
|
options.checkoutExtras?.(outputDir);
|
|
134
134
|
copySiteFiles(outputDir, options.siteFiles);
|
|
@@ -164,9 +164,9 @@ export function bundleFromCheckout(outputDir: string, options: PythonBundleOptio
|
|
|
164
164
|
path.join(packageRoot, "amplify/functions", options.functionDir, "handler.py"),
|
|
165
165
|
path.join(outputDir, "handler.py"),
|
|
166
166
|
);
|
|
167
|
-
for (const
|
|
168
|
-
fs.mkdirSync(path.join(outputDir,
|
|
169
|
-
fs.cpSync(path.join(packageRoot, "src",
|
|
167
|
+
for (const moduleName of options.modules) {
|
|
168
|
+
fs.mkdirSync(path.join(outputDir, moduleName), { recursive: true });
|
|
169
|
+
fs.cpSync(path.join(packageRoot, "src", moduleName), path.join(outputDir, moduleName), { recursive: true });
|
|
170
170
|
}
|
|
171
171
|
options.checkoutExtras?.(outputDir);
|
|
172
172
|
copySiteFiles(outputDir, options.siteFiles);
|
|
@@ -12,6 +12,22 @@ export type ReferenceCurationMetadataInput = {
|
|
|
12
12
|
referenceLineageId: string
|
|
13
13
|
decisionRelationId?: string | null
|
|
14
14
|
shareable?: boolean | null
|
|
15
|
+
actorKind?: CurationActorKind | null
|
|
16
|
+
sectionId?: string | null
|
|
17
|
+
delegation?: { delegationId: string; relayedBy: string; instruction: string } | null
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type CurationActorKind = "human" | "service"
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* A curation is human only when the caller signed in through the user pool, so
|
|
24
|
+
* AppSync supplied a verified subject claim. Request arguments never decide it;
|
|
25
|
+
* IAM-signed service callers and agents have no such claim.
|
|
26
|
+
*/
|
|
27
|
+
export function curationActorKind(identity: unknown): CurationActorKind {
|
|
28
|
+
const claims = (identity as {claims?: Record<string, unknown>} | null | undefined)?.claims
|
|
29
|
+
const subject = claims?.sub
|
|
30
|
+
return typeof subject === "string" && subject.trim() !== "" ? "human" : "service"
|
|
15
31
|
}
|
|
16
32
|
|
|
17
33
|
export function referenceCurationMetadata(input: ReferenceCurationMetadataInput): Record<string, unknown> {
|
|
@@ -23,7 +39,42 @@ export function referenceCurationMetadata(input: ReferenceCurationMetadataInput)
|
|
|
23
39
|
curationReasonCode: input.reasonCode,
|
|
24
40
|
referenceId: input.referenceId,
|
|
25
41
|
referenceLineageId: input.referenceLineageId,
|
|
42
|
+
...(input.actorKind ? {actorKind: input.actorKind} : {}),
|
|
43
|
+
...(input.sectionId?.trim() ? {sectionId: input.sectionId.trim()} : {}),
|
|
44
|
+
...(input.delegation
|
|
45
|
+
? {attestation: "delegated", relayedBy: input.delegation.relayedBy, delegationId: input.delegation.delegationId,
|
|
46
|
+
instruction: input.delegation.instruction}
|
|
47
|
+
: {}),
|
|
26
48
|
...(decisionRelationId ? {decisionRelationId} : {}),
|
|
27
49
|
...(decisionRelationId ? {shareable: input.shareable === true} : {}),
|
|
28
50
|
}
|
|
29
51
|
}
|
|
52
|
+
|
|
53
|
+
export type CurationSectionCandidate = {
|
|
54
|
+
id?: string | null
|
|
55
|
+
enabled?: boolean | null
|
|
56
|
+
enabledStatus?: string | null
|
|
57
|
+
} | null | undefined
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* A curation may name the newsroom Section the Reference belongs in, but only
|
|
61
|
+
* when it accepts the Reference and the Section exists and is enabled.
|
|
62
|
+
*/
|
|
63
|
+
export function validatedCurationSectionId(
|
|
64
|
+
requestedSectionId: string | null | undefined,
|
|
65
|
+
action: string,
|
|
66
|
+
section: CurationSectionCandidate,
|
|
67
|
+
): string | null {
|
|
68
|
+
const sectionId = requestedSectionId?.trim() || null
|
|
69
|
+
if (!sectionId) return null
|
|
70
|
+
if (action !== "accept") {
|
|
71
|
+
throw new Error("A section can be recorded only when accepting a reference.")
|
|
72
|
+
}
|
|
73
|
+
if (!section || section.id !== sectionId) {
|
|
74
|
+
throw new Error(`Newsroom section ${sectionId} was not found.`)
|
|
75
|
+
}
|
|
76
|
+
if (section.enabled === false || section.enabledStatus === "disabled") {
|
|
77
|
+
throw new Error(`Newsroom section ${sectionId} is disabled.`)
|
|
78
|
+
}
|
|
79
|
+
return sectionId
|
|
80
|
+
}
|
|
@@ -69,9 +69,9 @@ export function slackAgentInstructions(): string {
|
|
|
69
69
|
"",
|
|
70
70
|
"Be concise, accurate, and concrete. Slack has no web UI: do not use papyrus.web.navigate, papyrus.web.current_location, or assume the user can see papyrus:// pages.",
|
|
71
71
|
"",
|
|
72
|
-
"Raw console chat turns are working memory and are excluded from default semantic searches unless explicitly requested. When a chat produces durable
|
|
72
|
+
"Raw console chat turns are working memory and are excluded from default semantic searches unless explicitly requested. When a chat produces durable note, recommend creating a note Message instead of making every chat turn canonical knowledge.",
|
|
73
73
|
"",
|
|
74
|
-
"Respond openly to questions, commands, and discussion—the same conversational stance as the web console. Do not treat every message as a citation submission. Register references or create
|
|
74
|
+
"Respond openly to questions, commands, and discussion—the same conversational stance as the web console. Do not treat every message as a citation submission. Register references or create notes only when the user shares URLs/DOIs or asks you to file, summarize, or comment on specific material.",
|
|
75
75
|
"",
|
|
76
76
|
'For requests like "most recent references" or "tell me about recent references", do not ask clarifying questions first: immediately call execute_tactus with a Reference.list snippet, then summarize the results.',
|
|
77
77
|
"",
|
|
@@ -11,7 +11,7 @@ import { pythonLambdaCode } from "../functions/shared/python-bundle.js";
|
|
|
11
11
|
import { RENDITIONS_EPHEMERAL_STORAGE_MB, RENDITIONS_MEDIA_PREFIX, RENDITIONS_MEMORY_MB, RENDITIONS_TIMEOUT_SECONDS, renditionsEnvironment, renditionsEventPattern, } from "./renditions-settings.js";
|
|
12
12
|
const dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
13
13
|
const projectRoot = path.resolve(dirname, "../..");
|
|
14
|
-
export const renditionsRequirements = ["PyYAML>=6.0.2,<7", "citeproc-py>=0.8.2,<1", "anthus-markus==0.
|
|
14
|
+
export const renditionsRequirements = ["PyYAML>=6.0.2,<7", "citeproc-py>=0.8.2,<1", "anthus-markus==0.7.0", "Pillow>=11.3,<12"];
|
|
15
15
|
function installCheckoutRequirements(outputDir) {
|
|
16
16
|
const requirementsPath = path.join(projectRoot, "amplify/functions/renditions/requirements.txt");
|
|
17
17
|
execSync(`python3 -m pip install -r "${requirementsPath}" -t "${outputDir}" --no-cache-dir --platform manylinux2014_aarch64 --implementation cp --python-version 3.12 --only-binary=:all: --ignore-requires-python`, { cwd: projectRoot, stdio: "inherit" });
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
const dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
23
23
|
const projectRoot = path.resolve(dirname, "../..");
|
|
24
24
|
|
|
25
|
-
export const renditionsRequirements = ["PyYAML>=6.0.2,<7", "citeproc-py>=0.8.2,<1", "anthus-markus==0.
|
|
25
|
+
export const renditionsRequirements = ["PyYAML>=6.0.2,<7", "citeproc-py>=0.8.2,<1", "anthus-markus==0.7.0", "Pillow>=11.3,<12"];
|
|
26
26
|
|
|
27
27
|
export type RenditionsFunctionProps = {
|
|
28
28
|
siteBucket: s3.IBucket;
|
|
@@ -3,7 +3,7 @@ import { getSiteRenderer } from "../../../../../lib/site-renderer";
|
|
|
3
3
|
import { getCachedEditionItem, loadCachedEditionContent } from "../../../../../lib/cached-content-repository";
|
|
4
4
|
import { getEditionDatePath, parseEditionArticleRoute } from "../../../../../lib/edition-routes";
|
|
5
5
|
import { buildPresentationFooterEntries } from "../../../../../lib/presentation-footer";
|
|
6
|
-
import { SITE_BRAND } from "../../../../../lib/site-brand";
|
|
6
|
+
import { SITE_BRAND, editionsEnabled } from "../../../../../lib/site-brand";
|
|
7
7
|
import { generateEditionItemStaticParams } from "../../../../../lib/reader-static-params";
|
|
8
8
|
// Keep in sync with READER_REVALIDATE_SECONDS in lib/reader-route-config.ts
|
|
9
9
|
export const revalidate = 60;
|
|
@@ -39,6 +39,7 @@ export async function generateMetadata({ params }: DateScopedArticlePageProps) {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
export default async function DateScopedArticlePage({ params }: DateScopedArticlePageProps) {
|
|
42
|
+
if (!editionsEnabled()) notFound();
|
|
42
43
|
const { year, month, day, articleSlug } = await params;
|
|
43
44
|
const route = parseEditionArticleRoute({ year, month, day, articleSlug });
|
|
44
45
|
if (!route) notFound();
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { notFound, redirect } from "next/navigation";
|
|
2
|
+
import { editionsEnabled } from "../../../../lib/site-brand";
|
|
2
3
|
import { siteServesNextReaderRoutes } from "../../../../lib/reader-static-params";
|
|
3
4
|
import { getSiteRenderer } from "../../../../lib/site-renderer";
|
|
4
5
|
import type { PresentationTarget } from "../../../../renderers/pretext";
|
|
@@ -23,7 +24,7 @@ export async function EditionRoutePage({
|
|
|
23
24
|
lockedPresentation,
|
|
24
25
|
target = { kind: "edition" },
|
|
25
26
|
}: EditionRoutePageProps) {
|
|
26
|
-
if (!siteServesNextReaderRoutes()) notFound();
|
|
27
|
+
if (!editionsEnabled() || !siteServesNextReaderRoutes()) notFound();
|
|
27
28
|
const route = parseEditionDateRoute({ year, month, day });
|
|
28
29
|
if (!route) notFound();
|
|
29
30
|
if (!route.isCanonical) redirect(route.canonicalPath);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { notFound, redirect } from "next/navigation";
|
|
2
2
|
import { EditionRoutePage } from "../../edition-route-page";
|
|
3
3
|
import { parseEditionPageRoute } from "../../../../../../lib/edition-routes";
|
|
4
|
-
import { getDefaultPretextLayout, getForcedPresentation } from "../../../../../../lib/site-brand";
|
|
4
|
+
import { editionsEnabled, getDefaultPretextLayout, getForcedPresentation } from "../../../../../../lib/site-brand";
|
|
5
5
|
import { generateEditionPageStaticParams } from "../../../../../../lib/reader-static-params";
|
|
6
6
|
// Keep in sync with READER_REVALIDATE_SECONDS in lib/reader-route-config.ts
|
|
7
7
|
export const revalidate = 60;
|
|
@@ -20,6 +20,7 @@ type EditionPageRouteProps = {
|
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
export default async function EditionPageRoute({ params }: EditionPageRouteProps) {
|
|
23
|
+
if (!editionsEnabled()) notFound();
|
|
23
24
|
const { year, month, day, pageNumber } = await params;
|
|
24
25
|
const route = parseEditionPageRoute({ year, month, day, pageNumber });
|
|
25
26
|
if (!route) notFound();
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { notFound } from "next/navigation";
|
|
2
|
+
import { editionsEnabled } from "../../../../lib/site-brand";
|
|
1
3
|
import { EditionRoutePage } from "./edition-route-page";
|
|
2
4
|
import { generateEditionDateStaticParams } from "../../../../lib/reader-static-params";
|
|
3
5
|
|
|
@@ -17,6 +19,7 @@ type DateEditionPageProps = {
|
|
|
17
19
|
};
|
|
18
20
|
|
|
19
21
|
export default async function DateEditionPage({ params }: DateEditionPageProps) {
|
|
22
|
+
if (!editionsEnabled()) notFound();
|
|
20
23
|
const { year, month, day } = await params;
|
|
21
24
|
return <EditionRoutePage day={day} month={month} year={year} />;
|
|
22
25
|
}
|
|
@@ -2,6 +2,7 @@ import { notFound, redirect } from "next/navigation";
|
|
|
2
2
|
import { EditionRoutePage } from "../../edition-route-page";
|
|
3
3
|
import { createSectionKey } from "../../../../../../lib/edition-sections";
|
|
4
4
|
import { parseEditionSectionRoute } from "../../../../../../lib/edition-routes";
|
|
5
|
+
import { editionsEnabled } from "../../../../../../lib/site-brand";
|
|
5
6
|
import { generateEditionSectionStaticParams } from "../../../../../../lib/reader-static-params";
|
|
6
7
|
// Keep in sync with READER_REVALIDATE_SECONDS in lib/reader-route-config.ts
|
|
7
8
|
export const revalidate = 60;
|
|
@@ -20,6 +21,7 @@ type EditionSectionRouteProps = {
|
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
export default async function EditionSectionRoute({ params }: EditionSectionRouteProps) {
|
|
24
|
+
if (!editionsEnabled()) notFound();
|
|
23
25
|
const { year, month, day, sectionKey } = await params;
|
|
24
26
|
const normalizedSectionKey = createSectionKey(sectionKey);
|
|
25
27
|
const route = parseEditionSectionRoute({ year, month, day, sectionKey: normalizedSectionKey });
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { NextResponse } from "next/server";
|
|
2
|
+
import { editionsEnabled } from "../../../../lib/site-brand";
|
|
2
3
|
import { loadArchiveEditionPreviews, clampArchiveLimit } from "../../../../lib/archive-data";
|
|
3
4
|
import { ARCHIVE_BATCH_SIZE } from "../../../../lib/archive-types";
|
|
4
5
|
|
|
@@ -6,6 +7,7 @@ import { ARCHIVE_BATCH_SIZE } from "../../../../lib/archive-types";
|
|
|
6
7
|
export const revalidate = 60;
|
|
7
8
|
|
|
8
9
|
export async function GET(request: Request) {
|
|
10
|
+
if (!editionsEnabled()) return new NextResponse(null, { status: 404 });
|
|
9
11
|
const url = new URL(request.url);
|
|
10
12
|
const cursor = url.searchParams.get("cursor");
|
|
11
13
|
const requestedLimit = Number(url.searchParams.get("limit") ?? ARCHIVE_BATCH_SIZE);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { NextRequest } from "next/server";
|
|
2
|
+
import { handleProspectusPublishingAccountCreation } from "../../../../../lib/prospectus-sign-in-routes";
|
|
3
|
+
|
|
4
|
+
export const dynamic = "force-dynamic";
|
|
5
|
+
export const runtime = "nodejs";
|
|
6
|
+
|
|
7
|
+
export function POST(request: NextRequest) {
|
|
8
|
+
return handleProspectusPublishingAccountCreation(request);
|
|
9
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { NextResponse } from "next/server";
|
|
4
|
+
|
|
5
|
+
export const dynamic = "force-dynamic";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Local preview only: derives a story's Markus body through the real Python engine so directives render.
|
|
9
|
+
* Set PAPYRUS_PREVIEW_PYTHON to a Python that has Papyrus and its Markus extra installed.
|
|
10
|
+
*/
|
|
11
|
+
export async function POST(request: Request) {
|
|
12
|
+
if (process.env.NEXT_PUBLIC_PAPYRUS_LOCAL_PREVIEW !== "1") return new NextResponse(null, { status: 404 });
|
|
13
|
+
const python = process.env.PAPYRUS_PREVIEW_PYTHON?.trim();
|
|
14
|
+
if (!python) return NextResponse.json({ error: "PAPYRUS_PREVIEW_PYTHON is not set." }, { status: 501 });
|
|
15
|
+
const input = await request.text();
|
|
16
|
+
const script = path.join(process.cwd(), "scripts", "local-preview-derive.py");
|
|
17
|
+
const output = await new Promise<string>((resolve, reject) => {
|
|
18
|
+
const child = spawn(python, [script], { env: process.env });
|
|
19
|
+
let stdout = "";
|
|
20
|
+
let stderr = "";
|
|
21
|
+
child.stdout.on("data", chunk => { stdout += chunk; });
|
|
22
|
+
child.stderr.on("data", chunk => { stderr += chunk; });
|
|
23
|
+
child.on("error", reject);
|
|
24
|
+
child.on("close", code => code === 0 ? resolve(stdout) : reject(new Error(stderr || `derive exited with ${code}`)));
|
|
25
|
+
child.stdin.end(input);
|
|
26
|
+
}).catch((reason: unknown) => JSON.stringify({ error: reason instanceof Error ? reason.message : "derive failed" }));
|
|
27
|
+
return new NextResponse(output, { headers: { "content-type": "application/json" } });
|
|
28
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { NextResponse } from "next/server";
|
|
3
|
+
|
|
4
|
+
export const dynamic = "force-dynamic";
|
|
5
|
+
|
|
6
|
+
const CONTENT_TYPES: Record<string, string> = { jpg: "image/jpeg", jpeg: "image/jpeg", png: "image/png", gif: "image/gif", webp: "image/webp", svg: "image/svg+xml", avif: "image/avif" };
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Local preview only: streams one story image from the publication's storage bucket so the previews show real figures.
|
|
10
|
+
* Set PAPYRUS_PREVIEW_MEDIA_BUCKET to the bucket; the server's AWS credentials do the reading.
|
|
11
|
+
*/
|
|
12
|
+
export async function GET(request: Request) {
|
|
13
|
+
if (process.env.NEXT_PUBLIC_PAPYRUS_LOCAL_PREVIEW !== "1") return new NextResponse(null, { status: 404 });
|
|
14
|
+
const bucket = process.env.PAPYRUS_PREVIEW_MEDIA_BUCKET?.trim();
|
|
15
|
+
const key = new URL(request.url).searchParams.get("key") ?? "";
|
|
16
|
+
if (!bucket) return NextResponse.json({ error: "PAPYRUS_PREVIEW_MEDIA_BUCKET is not set." }, { status: 501 });
|
|
17
|
+
if (!/^media\/[A-Za-z0-9_\-./]+$/.test(key) || key.includes("..")) return new NextResponse(null, { status: 400 });
|
|
18
|
+
const extension = key.split(".").pop()?.toLowerCase() ?? "";
|
|
19
|
+
const child = spawn("aws", ["s3", "cp", `s3://${bucket}/${key}`, "-"], { env: process.env });
|
|
20
|
+
const chunks: Buffer[] = [];
|
|
21
|
+
child.stdout.on("data", chunk => chunks.push(chunk));
|
|
22
|
+
const exitCode = await new Promise<number>(resolve => { child.on("close", code => resolve(code ?? 1)); child.on("error", () => resolve(1)); });
|
|
23
|
+
if (exitCode !== 0) return new NextResponse(null, { status: 404 });
|
|
24
|
+
return new NextResponse(Buffer.concat(chunks), { headers: { "content-type": CONTENT_TYPES[extension] ?? "application/octet-stream", "cache-control": "private, max-age=300" } });
|
|
25
|
+
}
|
package/app/archive/page.tsx
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { notFound } from "next/navigation";
|
|
2
|
+
import { editionsEnabled } from "../../lib/site-brand";
|
|
1
3
|
import { ArchiveShell } from "../../components/archive-shell";
|
|
2
4
|
import { ArchiveGrid } from "../../components/archive-grid";
|
|
3
5
|
import { loadArchiveEditionPreviews } from "../../lib/archive-data";
|
|
@@ -7,6 +9,7 @@ import { ARCHIVE_BATCH_SIZE } from "../../lib/archive-types";
|
|
|
7
9
|
export const revalidate = 60;
|
|
8
10
|
|
|
9
11
|
export default async function ArchivePage() {
|
|
12
|
+
if (!editionsEnabled()) notFound();
|
|
10
13
|
const initialBatch = await loadArchiveEditionPreviews({ limit: ARCHIVE_BATCH_SIZE });
|
|
11
14
|
|
|
12
15
|
return (
|
package/app/globals.css
CHANGED
|
@@ -6275,7 +6275,7 @@ img {
|
|
|
6275
6275
|
padding-top: calc(var(--paper-rhythm) - 1px);
|
|
6276
6276
|
}
|
|
6277
6277
|
|
|
6278
|
-
.newsroom-list-detail-shell [data-news-desk-reference-detail] [data-reference-topic-workflow] + [data-reference-
|
|
6278
|
+
.newsroom-list-detail-shell [data-news-desk-reference-detail] [data-reference-topic-workflow] + [data-reference-note-workflow] {
|
|
6279
6279
|
border-top: 0;
|
|
6280
6280
|
padding-top: 0;
|
|
6281
6281
|
}
|
|
@@ -6476,7 +6476,7 @@ img {
|
|
|
6476
6476
|
|
|
6477
6477
|
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-workflow__input button,
|
|
6478
6478
|
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-workflow__header > button,
|
|
6479
|
-
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-
|
|
6479
|
+
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-note-shell > button {
|
|
6480
6480
|
background: transparent;
|
|
6481
6481
|
border: 1px solid rgb(var(--rule-rgb) / 0.42);
|
|
6482
6482
|
box-sizing: border-box;
|
|
@@ -6498,7 +6498,7 @@ img {
|
|
|
6498
6498
|
}
|
|
6499
6499
|
|
|
6500
6500
|
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-workflow__header > button:disabled,
|
|
6501
|
-
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-
|
|
6501
|
+
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-note-shell > button:disabled {
|
|
6502
6502
|
cursor: not-allowed;
|
|
6503
6503
|
opacity: 0.45;
|
|
6504
6504
|
}
|
|
@@ -6521,26 +6521,26 @@ img {
|
|
|
6521
6521
|
margin-right: calc(var(--paper-rhythm) * 0.5);
|
|
6522
6522
|
}
|
|
6523
6523
|
|
|
6524
|
-
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-
|
|
6524
|
+
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-note-form {
|
|
6525
6525
|
display: grid;
|
|
6526
6526
|
gap: 0;
|
|
6527
6527
|
width: 100%;
|
|
6528
6528
|
}
|
|
6529
6529
|
|
|
6530
|
-
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-
|
|
6530
|
+
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-note-shell {
|
|
6531
6531
|
display: grid;
|
|
6532
6532
|
gap: 0;
|
|
6533
6533
|
}
|
|
6534
6534
|
|
|
6535
|
-
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-
|
|
6535
|
+
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-note-shell > * + * {
|
|
6536
6536
|
margin-top: var(--paper-rhythm);
|
|
6537
6537
|
}
|
|
6538
6538
|
|
|
6539
|
-
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-
|
|
6539
|
+
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-note-form > * + * {
|
|
6540
6540
|
margin-top: var(--paper-rhythm);
|
|
6541
6541
|
}
|
|
6542
6542
|
|
|
6543
|
-
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-
|
|
6543
|
+
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-note-shell > button {
|
|
6544
6544
|
align-items: center;
|
|
6545
6545
|
appearance: none;
|
|
6546
6546
|
display: inline-flex;
|
|
@@ -6550,7 +6550,7 @@ img {
|
|
|
6550
6550
|
vertical-align: top;
|
|
6551
6551
|
}
|
|
6552
6552
|
|
|
6553
|
-
.newsroom-list-detail-shell [data-news-desk-reference-detail] [data-reference-
|
|
6553
|
+
.newsroom-list-detail-shell [data-news-desk-reference-detail] [data-reference-note-workflow] .news-desk-reference-workflow__header > button {
|
|
6554
6554
|
align-items: center;
|
|
6555
6555
|
appearance: none;
|
|
6556
6556
|
display: inline-flex;
|
|
@@ -6562,37 +6562,37 @@ img {
|
|
|
6562
6562
|
vertical-align: top;
|
|
6563
6563
|
}
|
|
6564
6564
|
|
|
6565
|
-
.newsroom-list-detail-shell [data-news-desk-reference-detail] [data-reference-
|
|
6565
|
+
.newsroom-list-detail-shell [data-news-desk-reference-detail] [data-reference-note-workflow] .news-desk-reference-workflow__header {
|
|
6566
6566
|
align-items: flex-start;
|
|
6567
6567
|
}
|
|
6568
6568
|
|
|
6569
|
-
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-
|
|
6569
|
+
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-note-list {
|
|
6570
6570
|
display: grid;
|
|
6571
6571
|
gap: 0;
|
|
6572
6572
|
}
|
|
6573
6573
|
|
|
6574
|
-
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-
|
|
6574
|
+
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-note-list .news-desk-reference-topic-state-row {
|
|
6575
6575
|
border-left: 0;
|
|
6576
6576
|
gap: 0;
|
|
6577
6577
|
padding-left: 0;
|
|
6578
6578
|
}
|
|
6579
6579
|
|
|
6580
|
-
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-
|
|
6580
|
+
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-note-list .news-desk-reference-topic-state-row + .news-desk-reference-topic-state-row {
|
|
6581
6581
|
margin-top: var(--paper-rhythm);
|
|
6582
6582
|
}
|
|
6583
6583
|
|
|
6584
|
-
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-
|
|
6585
|
-
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-
|
|
6584
|
+
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-note-list .news-desk-reference-topic-state-row__headline,
|
|
6585
|
+
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-note-list .news-desk-reference-topic-state-row__meta {
|
|
6586
6586
|
gap: 0;
|
|
6587
6587
|
}
|
|
6588
6588
|
|
|
6589
|
-
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-
|
|
6590
|
-
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-
|
|
6589
|
+
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-note-list .news-desk-reference-topic-state-row strong,
|
|
6590
|
+
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-note-list .news-desk-reference-topic-state-row span {
|
|
6591
6591
|
line-height: var(--paper-rhythm);
|
|
6592
6592
|
min-height: var(--paper-rhythm);
|
|
6593
6593
|
}
|
|
6594
6594
|
|
|
6595
|
-
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-
|
|
6595
|
+
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-note-form .news-desk-reference-curation-note {
|
|
6596
6596
|
display: grid;
|
|
6597
6597
|
gap: 0;
|
|
6598
6598
|
grid-template-rows: var(--paper-rhythm) auto;
|
|
@@ -6600,7 +6600,7 @@ img {
|
|
|
6600
6600
|
min-width: 0;
|
|
6601
6601
|
}
|
|
6602
6602
|
|
|
6603
|
-
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-
|
|
6603
|
+
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-note-form .news-desk-reference-curation-note span {
|
|
6604
6604
|
color: var(--muted-strong);
|
|
6605
6605
|
font-family: Arial, Helvetica, sans-serif;
|
|
6606
6606
|
font-size: 0.66rem;
|
|
@@ -6611,13 +6611,13 @@ img {
|
|
|
6611
6611
|
text-transform: uppercase;
|
|
6612
6612
|
}
|
|
6613
6613
|
|
|
6614
|
-
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-
|
|
6614
|
+
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-note-shell button {
|
|
6615
6615
|
line-height: var(--paper-rhythm);
|
|
6616
6616
|
min-height: var(--news-desk-detail-control-height);
|
|
6617
6617
|
}
|
|
6618
6618
|
|
|
6619
|
-
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-
|
|
6620
|
-
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-
|
|
6619
|
+
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-note-form .news-desk-reference-curation-note input,
|
|
6620
|
+
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-note-form .news-desk-reference-curation-note textarea {
|
|
6621
6621
|
box-sizing: border-box;
|
|
6622
6622
|
display: block;
|
|
6623
6623
|
font-family: Arial, Helvetica, sans-serif;
|
|
@@ -6627,7 +6627,7 @@ img {
|
|
|
6627
6627
|
padding: 0 calc(var(--paper-rhythm) * 0.5);
|
|
6628
6628
|
}
|
|
6629
6629
|
|
|
6630
|
-
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-
|
|
6630
|
+
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-note-form textarea {
|
|
6631
6631
|
background: rgb(var(--paper-rgb) / 0.42);
|
|
6632
6632
|
border: 1px solid rgb(var(--rule-rgb) / 0.32);
|
|
6633
6633
|
color: var(--ink);
|
|
@@ -6637,7 +6637,7 @@ img {
|
|
|
6637
6637
|
resize: vertical;
|
|
6638
6638
|
}
|
|
6639
6639
|
|
|
6640
|
-
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-
|
|
6640
|
+
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-note-form__actions {
|
|
6641
6641
|
align-items: center;
|
|
6642
6642
|
column-gap: calc(var(--paper-rhythm) * 0.5);
|
|
6643
6643
|
display: flex;
|
|
@@ -6646,7 +6646,7 @@ img {
|
|
|
6646
6646
|
min-height: var(--paper-rhythm);
|
|
6647
6647
|
}
|
|
6648
6648
|
|
|
6649
|
-
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-
|
|
6649
|
+
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-note-form__actions button {
|
|
6650
6650
|
background: transparent;
|
|
6651
6651
|
border: 1px solid rgb(var(--rule-rgb) / 0.42);
|
|
6652
6652
|
box-sizing: border-box;
|
|
@@ -6662,7 +6662,7 @@ img {
|
|
|
6662
6662
|
text-transform: uppercase;
|
|
6663
6663
|
}
|
|
6664
6664
|
|
|
6665
|
-
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-
|
|
6665
|
+
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-note-form__actions button:disabled {
|
|
6666
6666
|
cursor: not-allowed;
|
|
6667
6667
|
opacity: 0.45;
|
|
6668
6668
|
}
|
|
@@ -6895,11 +6895,11 @@ img {
|
|
|
6895
6895
|
justify-self: stretch;
|
|
6896
6896
|
}
|
|
6897
6897
|
|
|
6898
|
-
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-
|
|
6898
|
+
.newsroom-list-detail-shell [data-news-desk-reference-detail] .news-desk-reference-note-shell > button {
|
|
6899
6899
|
justify-self: stretch;
|
|
6900
6900
|
}
|
|
6901
6901
|
|
|
6902
|
-
.newsroom-list-detail-shell [data-news-desk-reference-detail] [data-reference-
|
|
6902
|
+
.newsroom-list-detail-shell [data-news-desk-reference-detail] [data-reference-note-workflow] .news-desk-reference-workflow__header {
|
|
6903
6903
|
align-items: flex-start;
|
|
6904
6904
|
flex-direction: row;
|
|
6905
6905
|
gap: var(--paper-rhythm);
|