-
Notifications
You must be signed in to change notification settings - Fork 3.7k
Expand file tree
/
Copy pathmeta.ts
More file actions
121 lines (110 loc) · 3.49 KB
/
meta.ts
File metadata and controls
121 lines (110 loc) · 3.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import type { Metadata } from 'next'
import type { Icon } from 'next/dist/lib/metadata/types/metadata-types.js'
import type { MetaConfig } from 'payload'
import { payloadFaviconDark, payloadFaviconLight, staticOGImage } from '@payloadcms/ui/assets'
import * as qs from 'qs-esm'
const getTitleString = (title: Metadata['title']): string | undefined => {
if (!title) {
return undefined
}
if (typeof title === 'string') {
return title
}
if ('absolute' in title) {
return title.absolute
}
return title.default
}
const defaultOpenGraph: Metadata['openGraph'] = {
description:
'Payload is a headless CMS and application framework built with TypeScript, Node.js, and React.',
siteName: 'Payload App',
title: 'Payload App',
}
export const generateMetadata = async (
args: { serverURL: string } & MetaConfig,
): Promise<Metadata> => {
const { defaultOGImageType, serverURL, titleSuffix, ...rest } = args
/**
* @todo find a way to remove the type assertion here.
* It is a result of needing to `DeepCopy` the `MetaConfig` type from Payload.
* This is required for the `DeepRequired` from `Config` to `SanitizedConfig`.
*/
const incomingMetadata = rest as Metadata
const icons: Metadata['icons'] =
incomingMetadata.icons ||
([
{
type: 'image/png',
rel: 'icon',
sizes: '32x32',
url: typeof payloadFaviconDark === 'object' ? payloadFaviconDark?.src : payloadFaviconDark,
},
{
type: 'image/png',
media: '(prefers-color-scheme: dark)',
rel: 'icon',
sizes: '32x32',
url:
typeof payloadFaviconLight === 'object' ? payloadFaviconLight?.src : payloadFaviconLight,
},
] satisfies Array<Icon>)
const metaTitle: Metadata['title'] =
typeof incomingMetadata.title === 'object' && incomingMetadata.title !== null
? incomingMetadata.title
: [getTitleString(incomingMetadata.title), titleSuffix].filter(Boolean).join(' ') || undefined
const titleStringForOg: string | undefined =
typeof incomingMetadata.openGraph?.title === 'string'
? incomingMetadata.openGraph.title
: getTitleString(incomingMetadata.title)
const ogTitle = [titleStringForOg, titleSuffix].filter(Boolean).join(' ')
const mergedOpenGraph: Metadata['openGraph'] = {
...(defaultOpenGraph || {}),
...(defaultOGImageType === 'dynamic'
? {
images: [
{
alt: ogTitle,
height: 630,
url: `/api/og${qs.stringify(
{
description:
incomingMetadata.openGraph?.description || defaultOpenGraph.description,
title: ogTitle,
},
{
addQueryPrefix: true,
},
)}`,
width: 1200,
},
],
}
: {}),
...(defaultOGImageType === 'static'
? {
images: [
{
alt: ogTitle,
height: 480,
url: typeof staticOGImage === 'object' ? staticOGImage?.src : staticOGImage,
width: 640,
},
],
}
: {}),
title: ogTitle,
...(incomingMetadata.openGraph || {}),
}
return Promise.resolve({
...incomingMetadata,
icons,
metadataBase: new URL(
serverURL ||
process.env.PAYLOAD_PUBLIC_SERVER_URL ||
`http://localhost:${process.env.PORT || 3000}`,
),
openGraph: mergedOpenGraph,
title: metaTitle,
})
}