@justanarthur/payload-www 0.1.1
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/README.md +381 -0
- package/dist/access.d.ts +11 -0
- package/dist/access.js +34 -0
- package/dist/blocks.d.ts +24 -0
- package/dist/blocks.js +75 -0
- package/dist/collections.d.ts +200 -0
- package/dist/collections.js +625 -0
- package/dist/components.d.ts +6 -0
- package/dist/components.js +38 -0
- package/dist/config.d.ts +100 -0
- package/dist/config.js +914 -0
- package/dist/core-access.d.ts +11 -0
- package/dist/core-access.js +34 -0
- package/dist/core-blocks.d.ts +24 -0
- package/dist/core-blocks.js +75 -0
- package/dist/core-fields.d.ts +36 -0
- package/dist/core-fields.js +134 -0
- package/dist/core-utils.d.ts +16 -0
- package/dist/core-utils.js +59 -0
- package/dist/data-collections.d.ts +200 -0
- package/dist/data-collections.js +625 -0
- package/dist/data-seed.d.ts +76 -0
- package/dist/data-seed.js +212 -0
- package/dist/data-test.d.ts +30 -0
- package/dist/data-test.js +1018 -0
- package/dist/fields.d.ts +36 -0
- package/dist/fields.js +134 -0
- package/dist/globals.d.ts +48 -0
- package/dist/globals.js +228 -0
- package/dist/hooks.d.ts +108 -0
- package/dist/hooks.js +196 -0
- package/dist/imagehash.d.ts +3 -0
- package/dist/imagehash.js +24 -0
- package/dist/import-map-provider.d.ts +20 -0
- package/dist/import-map-provider.js +26 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +38 -0
- package/dist/metadata.d.ts +122 -0
- package/dist/metadata.js +335 -0
- package/dist/pages.d.ts +323 -0
- package/dist/pages.js +1016 -0
- package/dist/render-components.d.ts +42 -0
- package/dist/render-components.js +144 -0
- package/dist/render-metadata.d.ts +122 -0
- package/dist/render-metadata.js +335 -0
- package/dist/render-pages.d.ts +574 -0
- package/dist/render-pages.js +1450 -0
- package/dist/render-utils.d.ts +158 -0
- package/dist/render-utils.js +341 -0
- package/dist/seed.d.ts +76 -0
- package/dist/seed.js +212 -0
- package/dist/server.d.ts +922 -0
- package/dist/server.js +2055 -0
- package/dist/test.d.ts +30 -0
- package/dist/test.js +1018 -0
- package/dist/translator.d.ts +2 -0
- package/dist/translator.js +24 -0
- package/dist/utils.d.ts +16 -0
- package/dist/utils.js +59 -0
- package/dist/with-www-config.d.ts +100 -0
- package/dist/with-www-config.js +914 -0
- package/package.json +246 -0
package/README.md
ADDED
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
# @justanarthur/payload-www
|
|
2
|
+
|
|
3
|
+
Reusable Payload CMS website template. Wires collections, globals,
|
|
4
|
+
blocks, fields, access, hooks, metadata (JSON-LD, hreflang), and
|
|
5
|
+
Next.js page renderers behind a single `createWWWConfig({ locales, blocks })`
|
|
6
|
+
composer. The lib consumes your [next-intl](https://next-intl.dev) routing
|
|
7
|
+
config so locale validation, URL shape, hreflang alternates, and the
|
|
8
|
+
language switcher share a single source of truth with the rest of your app.
|
|
9
|
+
|
|
10
|
+
## What's inside
|
|
11
|
+
|
|
12
|
+
- **Composer** — `createWWWConfig({ locales, blocks, defaultPlugins? })` returns `{ withWWWConfig }`. One composer call is enough for the most common cases.
|
|
13
|
+
- **Collections** — `Pages` (title, blocks tab, slug, drafts, revalidation hook), `Posts` (title, excerpt, richText, drafts, revalidation hook), `StaticPages` (system pages — 404, 500, search-empty, … — addressed by a `kind` discriminator, not a slug)
|
|
14
|
+
- **Globals** — `Header` and `Footer` (both `nav` blocks with `navColumn` / `navItem`)
|
|
15
|
+
- **Default render components** — `PagesPage`, `HeaderPage`, `FooterPage` Server Components. Override any of them by setting a different `custom.path` on the collection / global.
|
|
16
|
+
- **LivePreviewListener** — built in. The lib's `createCollectionPageExports` default page renders it (via `React.lazy` so the server dist stays free of `'use client'` imports) whenever Next.js draft mode is on. Hosts get live preview automatically — no opt-in required. The component itself is also exported from `/render-components` for hosts that want to mount it elsewhere.
|
|
17
|
+
- **Hooks** — `createRevalidateCollectionHook(opts)` (canonical factory for **all** collections: Pages, Posts, host-defined; per-locale `revalidatePath` fan-out + `revalidateTag('collection_<slug>_<id>', 'max')` + sitemap tag, with a `pathMode: 'tag-only'` mode for collections without a URL like `staticPages`), `createRevalidatePageHooks()` (deprecated alias for Pages preset), `createRevalidateGlobalHook(slug)` (per-locale tag for globals)
|
|
18
|
+
- **Access** — `anyone`, `authenticated`, `authenticatedOrPublished`
|
|
19
|
+
- **Fields** — `link`, `linkGroup` (with `disableLabel` / `appearances` / `localized` / `relationTo` / `overrides` options)
|
|
20
|
+
- **Metadata** — `buildArticleLd`, `buildBreadcrumbsLd`, `buildOrganizationLd`, `buildHreflangAlternates`, slug transforms, `queryDocBySlug` / `queryAllDocs` / `queryAllLocaleSlugs`
|
|
21
|
+
- **Pages** — `createCollectionPageExports` (Next.js App Router render factory), `addCollectionsToSitemap`. Supports a `showcase` sidebar and a `homeExtras` callback for the home route.
|
|
22
|
+
- **Components** — `LivePreviewListener`, `RenderBlocks`, `PageShowcase` (sidebar layout for demos / previews), `LocaleSwitcher` (server-renderable nav built from the page's hreflang alternates)
|
|
23
|
+
- **Route handlers** — `createPreviewHandler` (from the `/render-utils` subpath). The Next.js sitemap convention ships as `createSitemapFile` (same subpath) — it's a `MetadataRoute.Sitemap` factory for `app/(frontend)/sitemap.ts`, not a route handler, and it's `localePrefix`-aware.
|
|
24
|
+
- **Utils** — `getFromImportMap`, `generateImportName`, `renderCollectionModule`
|
|
25
|
+
- **Seed / Test** — `createBaseSeed` (publishes by default — pass `status: 'draft'` to keep a doc as a draft), `createTestPayload`
|
|
26
|
+
|
|
27
|
+
## Quick start
|
|
28
|
+
|
|
29
|
+
### 1. Wire the composer
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
// payload.config.ts
|
|
33
|
+
import { buildConfig } from 'payload'
|
|
34
|
+
import { createWWWConfig } from '@justanarthur/payload-www/with-www-config'
|
|
35
|
+
import { MyCtaBlock, MyHeroBlock, MyRichTextBlock } from './blocks'
|
|
36
|
+
|
|
37
|
+
const { withWWWConfig } = createWWWConfig({
|
|
38
|
+
locales: ['en', 'sk', 'de'],
|
|
39
|
+
blocks: [MyCtaBlock, MyHeroBlock, MyRichTextBlock]
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
export default buildConfig(
|
|
43
|
+
withWWWConfig({
|
|
44
|
+
collections: [], // optional extra collections
|
|
45
|
+
globals: [], // optional extra globals
|
|
46
|
+
// ...rest of your config
|
|
47
|
+
})
|
|
48
|
+
)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`withWWWConfig` injects `Pages`, `Header`, and `Footer` plus the lib's
|
|
52
|
+
default plugin set (seoPlugin, imageHashPlugin, translator). Use the
|
|
53
|
+
`defaultPlugins` callback to drop or extend the list:
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
createWWWConfig({
|
|
57
|
+
locales: ['en', 'sk', 'de'],
|
|
58
|
+
blocks: [MyCtaBlock],
|
|
59
|
+
defaultPlugins: (defaults) => defaults.filter((p) => p !== translator)
|
|
60
|
+
})
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 2. Define your next-intl routing
|
|
64
|
+
|
|
65
|
+
The lib reads the same routing config next-intl uses, so URL shape,
|
|
66
|
+
locale validation, hreflang alternates, and the language switcher share
|
|
67
|
+
a single source of truth:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
// src/i18n/routing.ts
|
|
71
|
+
import { defineRouting } from 'next-intl/routing'
|
|
72
|
+
|
|
73
|
+
export const routing = defineRouting({
|
|
74
|
+
locales: ['en', 'uk'],
|
|
75
|
+
defaultLocale: 'en',
|
|
76
|
+
// 'as-needed' means `/about` for the default locale and
|
|
77
|
+
// `/uk/about` for the others — the lib mirrors this in
|
|
78
|
+
// hreflang alternates and the language switcher.
|
|
79
|
+
localePrefix: 'as-needed',
|
|
80
|
+
labels: { en: 'English', uk: 'Українська' }
|
|
81
|
+
})
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 3. Page exports
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
// app/(frontend)/[locale]/page.tsx — home
|
|
88
|
+
// app/(frontend)/[locale]/[...slug]/page.tsx — catch-all
|
|
89
|
+
import { createCollectionPageExports } from '@justanarthur/payload-www/render-pages'
|
|
90
|
+
import configPromise from '@payload-config'
|
|
91
|
+
import { importMap } from '@/app/(payload)/admin/importMap.js'
|
|
92
|
+
import { routing } from '@/i18n/routing'
|
|
93
|
+
|
|
94
|
+
import { getServerSideURL } from '@/utilities/getURL'
|
|
95
|
+
|
|
96
|
+
const generateMeta = async ({ doc }) => ({ title: doc?.title })
|
|
97
|
+
|
|
98
|
+
const { default: Page, generateMetadata, generateStaticParams } =
|
|
99
|
+
createCollectionPageExports(
|
|
100
|
+
{ config: configPromise, importMap, routing },
|
|
101
|
+
{ getServerSideURL, generateMeta }
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
export default Page
|
|
105
|
+
export { generateMetadata, generateStaticParams }
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The lib auto-mounts its `LivePreviewListener` (loaded via `React.lazy`
|
|
109
|
+
so the server dist stays free of `'use client'` imports) whenever
|
|
110
|
+
Next.js draft mode is on. No opt-in required.
|
|
111
|
+
|
|
112
|
+
#### Showcase sidebar + home extras
|
|
113
|
+
|
|
114
|
+
The home route can render inside a `<PageShowcase>` two-column layout
|
|
115
|
+
(sidebar with metadata, JSON-LD, and a language switcher) and append a
|
|
116
|
+
`homeExtras` block (recent pages, recent posts, etc.):
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
const { default: Page, generateMetadata, generateStaticParams } =
|
|
120
|
+
createCollectionPageExports(
|
|
121
|
+
{ config: configPromise, importMap, routing },
|
|
122
|
+
{
|
|
123
|
+
getServerSideURL,
|
|
124
|
+
generateMeta,
|
|
125
|
+
showcase: { enabled: true }, // wrap in <PageShowcase>
|
|
126
|
+
homeExtras: async ({ locale }) => {
|
|
127
|
+
const { pages, posts } = await fetchRecent(locale)
|
|
128
|
+
return <RecentLists pages={pages} posts={posts} />
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
`<PageShowcase>` and `<LocaleSwitcher>` are also exported individually
|
|
135
|
+
(from `/render-components` and `/render-utils` respectively) for hosts
|
|
136
|
+
that want to drop them in their own layouts.
|
|
137
|
+
|
|
138
|
+
### 4. Route handlers — preview + sitemap
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
// src/proxy.ts (replaces the deprecated src/middleware.ts)
|
|
142
|
+
import createMiddleware from 'next-intl/middleware'
|
|
143
|
+
import { routing } from '@/i18n/routing'
|
|
144
|
+
export default createMiddleware(routing)
|
|
145
|
+
export const config = {
|
|
146
|
+
matcher: ['/', '/((?!api|_next|_vercel|admin|next|.*\\..*).*)']
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
// app/(payload)/next/preview/route.ts
|
|
152
|
+
import { createPreviewHandler } from '@justanarthur/payload-www/render-utils'
|
|
153
|
+
export const GET = createPreviewHandler()
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
// app/(frontend)/sitemap.ts
|
|
158
|
+
import { createSitemapFile } from '@justanarthur/payload-www/render-utils'
|
|
159
|
+
import configPromise from '@payload-config'
|
|
160
|
+
import { getServerSideURL } from '@/utilities/getURL'
|
|
161
|
+
|
|
162
|
+
// One file, all collections, all locales — Next.js serves it at
|
|
163
|
+
// /sitemap.xml. The Pages collection's `afterChange` hook invalidates
|
|
164
|
+
// the `pages-sitemap` tag the factory reads from, so edits refresh
|
|
165
|
+
// the sitemap automatically.
|
|
166
|
+
export default createSitemapFile({
|
|
167
|
+
collections: ['pages', 'posts'],
|
|
168
|
+
config: configPromise,
|
|
169
|
+
getServerSideURL,
|
|
170
|
+
// 'as-needed' makes the default locale render without a prefix
|
|
171
|
+
// (`/about`), other locales prefixed (`/uk/about`). Matches the
|
|
172
|
+
// host's next-intl `localePrefix` so sitemap URLs match the
|
|
173
|
+
// actual route shape.
|
|
174
|
+
localePrefix: 'as-needed',
|
|
175
|
+
// Collections mounted under a sub-route (here: Posts at
|
|
176
|
+
// `/posts/[...slug]`) need their sitemap URLs prefixed so they
|
|
177
|
+
// match the real route. Pages live at the root, so no prefix.
|
|
178
|
+
urlPrefixes: { posts: '/posts' }
|
|
179
|
+
})
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
The Pages collection's `afterChange` hook revalidates the
|
|
183
|
+
`pages-sitemap` tag the sitemap factory reads from.
|
|
184
|
+
|
|
185
|
+
### 5. System pages (404, 500, search-empty, …)
|
|
186
|
+
|
|
187
|
+
The lib ships a `StaticPages` collection for pages that don't map to a
|
|
188
|
+
slug-based URL. One row per `kind` discriminator (`'not-found'`,
|
|
189
|
+
`'server-error'`, `'search-empty'`, `'offline'`). The host's route
|
|
190
|
+
file fetches the row and renders it via `createStaticPageExports` —
|
|
191
|
+
the same shape as `createCollectionPageExports`, minus the
|
|
192
|
+
metadata / sitemap / static-params plumbing (system pages have no
|
|
193
|
+
URL):
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
// app/(frontend)/[locale]/not-found.tsx
|
|
197
|
+
import configPromise from '@payload-config'
|
|
198
|
+
import { createStaticPageExports } from '@justanarthur/payload-www/render-pages'
|
|
199
|
+
import { importMap } from '@/app/(payload)/admin/importMap.js'
|
|
200
|
+
|
|
201
|
+
const { default: NotFound } = createStaticPageExports({
|
|
202
|
+
config: configPromise,
|
|
203
|
+
importMap,
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
export default NotFound
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
`createStaticPageExports` reads the active locale via
|
|
210
|
+
`getLocale()` from `next-intl/server` (Next.js passes no props to
|
|
211
|
+
not-found components, so the URL-segment locale comes from the
|
|
212
|
+
request config — middleware sets it, the host's `i18n/request.ts`
|
|
213
|
+
falls back to `defaultLocale` for invalid values). Adding a
|
|
214
|
+
`server-error.tsx` is the same shape with `kind: 'server-error'`.
|
|
215
|
+
|
|
216
|
+
Editors create the row in admin (under the `System` group), pick a
|
|
217
|
+
`kind`, and populate the `blocks` tab using the same block set you
|
|
218
|
+
passed to `createWWWConfig({ blocks })`. The `title` field is
|
|
219
|
+
admin-only — not rendered. `kind` is `unique`, so the database
|
|
220
|
+
enforces one row per system page. Drafts + autosave mirror `pages`.
|
|
221
|
+
The translator plugin includes `'static-pages'` in its default
|
|
222
|
+
`collections` list, so SK content fills automatically when you expand
|
|
223
|
+
`localization.locales`.
|
|
224
|
+
|
|
225
|
+
Revalidation uses the `pathMode: 'tag-only'` branch of
|
|
226
|
+
`createRevalidateCollectionHook` — no URL fan-out (system pages have
|
|
227
|
+
no slug), but the per-id tag (`collection_static-pages_<id>`) and the
|
|
228
|
+
collection-wide tag (`static-pages` via the `sitemapTag` override)
|
|
229
|
+
fire on every change.
|
|
230
|
+
|
|
231
|
+
## Public API
|
|
232
|
+
|
|
233
|
+
The root import gives you the full surface:
|
|
234
|
+
|
|
235
|
+
```ts
|
|
236
|
+
import {
|
|
237
|
+
createWWWConfig, // composer (default export)
|
|
238
|
+
createPagesCollection, // collection factories
|
|
239
|
+
createPostsCollection,
|
|
240
|
+
createStaticPagesCollection,
|
|
241
|
+
createHeaderGlobal,
|
|
242
|
+
createFooterGlobal,
|
|
243
|
+
generatePreviewPath, // admin.preview URL builder
|
|
244
|
+
HOME_PAGE_SLUG, PAGES_SLUG, POSTS_SLUG, STATIC_PAGES_SLUG,
|
|
245
|
+
link, linkGroup, // fields
|
|
246
|
+
appearanceOptions,
|
|
247
|
+
anyone, authenticated, // access
|
|
248
|
+
authenticatedOrPublished,
|
|
249
|
+
createRevalidatePageHooks, // hooks
|
|
250
|
+
createRevalidateCollectionHook, // hooks (canonical; createRevalidatePageHooks is a deprecated Pages preset)
|
|
251
|
+
createRevalidateGlobalHook,
|
|
252
|
+
buildArticleLd, // metadata
|
|
253
|
+
buildBreadcrumbsLd,
|
|
254
|
+
buildOrganizationLd,
|
|
255
|
+
buildHreflangAlternates,
|
|
256
|
+
queryDocBySlug, queryAllDocs, queryAllLocaleSlugs,
|
|
257
|
+
segmentsToStoredSlug, segmentsToUrlPath, storedSlugToSegments,
|
|
258
|
+
getUrlPath, buildCanonicalUrl,
|
|
259
|
+
createCollectionPageExports, // page factory
|
|
260
|
+
addCollectionsToSitemap,
|
|
261
|
+
LivePreviewListener, RenderBlocks, // components
|
|
262
|
+
PageShowcase, LocaleSwitcher, // demo / preview components
|
|
263
|
+
getFromImportMap, generateImportName, renderCollectionModule, // utils
|
|
264
|
+
createBaseSeed, createTestPayload, // dev
|
|
265
|
+
// constants
|
|
266
|
+
PAGES_RENDER_PATH, HEADER_RENDER_PATH, FOOTER_RENDER_PATH, PAGES_SITEMAP_TAG
|
|
267
|
+
} from '@justanarthur/payload-www'
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Subpath imports:
|
|
271
|
+
|
|
272
|
+
| Subpath | What's there |
|
|
273
|
+
|----------------------------------|-------------------------------------------------------------|
|
|
274
|
+
| `@justanarthur/payload-www` | root: `LivePreviewListener` only (client-safe) |
|
|
275
|
+
| `@justanarthur/payload-www/server` | everything else |
|
|
276
|
+
| `@justanarthur/payload-www/with-www-config` | `createWWWConfig` (default export) |
|
|
277
|
+
| `@justanarthur/payload-www/collections` | `createPagesCollection`, `createHeaderGlobal`, `createFooterGlobal` |
|
|
278
|
+
| `@justanarthur/payload-www/globals` | `createHeaderGlobal`, `createFooterGlobal` |
|
|
279
|
+
| `@justanarthur/payload-www/hooks` | revalidation hooks |
|
|
280
|
+
| `@justanarthur/payload-www/pages` | `createCollectionPageExports`, `addCollectionsToSitemap` |
|
|
281
|
+
| `@justanarthur/payload-www/render-pages` | same as `/pages` + `PagesPage` / `HeaderPage` / `FooterPage` / `PageShowcase` |
|
|
282
|
+
| `@justanarthur/payload-www/render-utils` | `createPreviewHandler`, `createSitemapFile`, `LivePreviewListener`, `LocaleSwitcher` |
|
|
283
|
+
| `@justanarthur/payload-www/render-components` | `LivePreviewListener` |
|
|
284
|
+
| `@justanarthur/payload-www/render-metadata` | JSON-LD + hreflang + slug utilities |
|
|
285
|
+
| `@justanarthur/payload-www/metadata` | same as `/render-metadata` |
|
|
286
|
+
| `@justanarthur/payload-www/fields` | `link`, `linkGroup`, `appearanceOptions` |
|
|
287
|
+
| `@justanarthur/payload-www/access` | `anyone`, `authenticated`, `authenticatedOrPublished` |
|
|
288
|
+
| `@justanarthur/payload-www/blocks` | `RenderBlocks` |
|
|
289
|
+
| `@justanarthur/payload-www/components` | `LivePreviewListener` |
|
|
290
|
+
| `@justanarthur/payload-www/utils` | `getFromImportMap`, `generateImportName`, `renderCollectionModule` |
|
|
291
|
+
| `@justanarthur/payload-www/seed` | `createBaseSeed` |
|
|
292
|
+
| `@justanarthur/payload-www/test` | `createTestPayload` |
|
|
293
|
+
| `@justanarthur/payload-www/data-seed` | same as `/seed` |
|
|
294
|
+
| `@justanarthur/payload-www/data-test` | same as `/test` |
|
|
295
|
+
| `@justanarthur/payload-www/data-collections` | collection factories |
|
|
296
|
+
| `@justanarthur/payload-www/config` | `createWWWConfig` (default export) |
|
|
297
|
+
| `@justanarthur/payload-www/imagehash` | `imageHashPlugin` re-export |
|
|
298
|
+
| `@justanarthur/payload-www/translator` | `translator` re-export |
|
|
299
|
+
|
|
300
|
+
## Configuration reference
|
|
301
|
+
|
|
302
|
+
`createWWWConfig({ ... })`:
|
|
303
|
+
|
|
304
|
+
| Option | Type | Required | Description |
|
|
305
|
+
|------------------|-----------------------------------|----------|------------------------------------------------------------------------|
|
|
306
|
+
| `locales` | `string[]` | yes | Locale list. First entry is the default locale (translation source). |
|
|
307
|
+
| `routing` | `PageRouting` | no | The host's next-intl `defineRouting({...})` result. When passed, `locales`, `defaultLocale`, and `localePrefix` are read from this object. `localePrefix` accepts both the simple string form and next-intl's verbose `{ mode, prefixes? }` shape (normalized internally). |
|
|
308
|
+
| `blocks` | `Block[]` | yes | Blocks the Pages collection accepts. |
|
|
309
|
+
| `linkRelationTo` | `string[]` | no | Collection slugs the Header / Footer nav links can reference. Default: `['pages']`. |
|
|
310
|
+
| `registerPosts` | `boolean` | no | Register the lib's Posts collection. Default `true`. |
|
|
311
|
+
| StaticPages | — | yes | Always registered (every site has 404). Hosts filter it out in `collections:` to opt. |
|
|
312
|
+
| `defaultPlugins` | `(defaults: Plugin[]) => Plugin[]`| no | Final say on the default `[seoPlugin, imageHashPlugin, translator]` list. |
|
|
313
|
+
|
|
314
|
+
`createRevalidateCollectionHook({ collectionSlug, urlPathPrefix?, sitemapTag?, localePrefix?, defaultLocale? })`:
|
|
315
|
+
|
|
316
|
+
| Option | Type | Description |
|
|
317
|
+
|------------------|-----------------------------------|------------------------------------------------------------------------|
|
|
318
|
+
| `collectionSlug` | `string` | Required. The collection's slug. Used in the `collection_<slug>_<id>` tag. |
|
|
319
|
+
| `urlPathPrefix` | `string` | URL path prefix. `''` for root-mounted (Pages), `'/posts'` for Posts. Default `''`. |
|
|
320
|
+
| `sitemapTag` | `string \| false` | Tag fired alongside paths. Default `${collectionSlug}-sitemap`. Pass `false` to opt out. |
|
|
321
|
+
| `localePrefix` | `'always' \| 'as-needed' \| 'never'` | Mirrors next-intl. Default `'always'`. Set to `'as-needed'` (with `defaultLocale`) when the host uses as-needed routing. |
|
|
322
|
+
| `defaultLocale` | `string` | Default locale for `localePrefix: 'as-needed'`. Falls back to `req.payload.config.localization.defaultLocale`. |
|
|
323
|
+
| `pathMode` | `'url' \| 'tag-only'` | Default `'url'` — fans out `revalidatePath` per locale × slug. Set `'tag-only'` for collections without a URL (e.g. `staticPages`); the hook still fires the per-id tag (`collection_<slug>_<id>`) and the collection-wide tag (via `sitemapTag`). |
|
|
324
|
+
|
|
325
|
+
The canonical hook for all collections — Pages, Posts, and host-defined. Pages internally uses this with `collectionSlug: 'pages'`, `urlPathPrefix: ''`. Fires `revalidatePath` for **every** declared locale (not just the request locale), handles slug renames while published, fires `revalidateTag('collection_<slug>_<id>', 'max')` for hosts that cache by id, and respects `req.context.disableRevalidate` for seed scripts.
|
|
326
|
+
|
|
327
|
+
`createRevalidatePageHooks()` is a deprecated alias for `createRevalidateCollectionHook({ collectionSlug: 'pages', urlPathPrefix: '' })` — kept for backward compat with hosts that imported this name directly.
|
|
328
|
+
|
|
329
|
+
`createCollectionPageExports({ config, importMap, slug?, renderPath?, routing }, deps, options?)`:
|
|
330
|
+
|
|
331
|
+
| Param | Type | Description |
|
|
332
|
+
|--------------|-----------------|------------------------------------------------------------------------|
|
|
333
|
+
| `config` | `Promise<SanitizedConfig>` | Resolved Payload config from `payload.config.ts` |
|
|
334
|
+
| `importMap` | `ImportMap` | The host's `app/(payload)/admin/importMap.js` |
|
|
335
|
+
| `slug` | `string` | Default `'pages'` |
|
|
336
|
+
| `renderPath` | `string` | Override the lib's `PAGES_RENDER_PATH` |
|
|
337
|
+
| `routing` | `PageRouting` | The host's `defineRouting({...})` result — drives URL building, hreflang, and the language switcher |
|
|
338
|
+
| `deps.getServerSideURL` | `() => string` | Host's absolute URL helper |
|
|
339
|
+
| `deps.generateMeta` | `(args) => Promise<Metadata>` | Host's metadata composer |
|
|
340
|
+
| `deps.notFoundOnMissing` | `boolean` | Default `true` — render 404 for unknown slugs |
|
|
341
|
+
| `deps.showcase` | `ShowcaseOptions \| false` | When `{ enabled: true }`, wraps the body in `<PageShowcase>` |
|
|
342
|
+
| `deps.homeExtras` | `(args) => ReactNode \| Promise<ReactNode>` | Content appended to the home route (slug = `''`) |
|
|
343
|
+
| `options.jsonLd` | `boolean \| JsonLdEntry[]` | Default `{ type: 'website' }` for every page |
|
|
344
|
+
| `options.changefreq` | `string` | Default `'weekly'` |
|
|
345
|
+
| `options.priority` | `number` | Default `0.5` |
|
|
346
|
+
| `options.websiteName` | `string` | Override the auto-generated `WebSite` JSON-LD `name` |
|
|
347
|
+
|
|
348
|
+
`createSitemapFile({ ... })`:
|
|
349
|
+
|
|
350
|
+
| Option | Type | Description |
|
|
351
|
+
|-----------------|-----------------|------------------------------------------------------------------------|
|
|
352
|
+
| `collections` | `string[]` | Collection slugs whose docs appear in the sitemap |
|
|
353
|
+
| `config` | `Promise<any>` | The Payload config promise |
|
|
354
|
+
| `getServerSideURL` | `() => string` | Host's absolute URL helper |
|
|
355
|
+
| `localePrefix` | `'always' \| 'as-needed' \| 'never'` | Default `'always'`. Mirrors next-intl's `localePrefix` so the sitemap URLs match the host's route shape. With `'as-needed'`, the default locale renders without a prefix. |
|
|
356
|
+
| `locales` | `string[]` | Optional locale filter. Defaults to every `config.localization.locales`. |
|
|
357
|
+
| `urlPrefixes` | `Record<string, string>` | Per-collection URL path prefix. Default `''`. Pass `{ posts: '/posts' }` for a collection mounted under a sub-route. |
|
|
358
|
+
| `perCollection` | `Record<string, { priority?, changefreq? }>` | Per-collection overrides |
|
|
359
|
+
|
|
360
|
+
## Migration notes
|
|
361
|
+
|
|
362
|
+
- `src/middleware.ts` is deprecated in favor of `src/proxy.ts` (next-intl ≥4). The lib doesn't ship a middleware — wire `createMiddleware(routing)` in your own `proxy.ts`.
|
|
363
|
+
- `PageRouting` is a new required arg on `createCollectionPageExports`. It's a structural subset of the next-intl `defineRouting` result (locales, defaultLocale, localePrefix, labels), so passing your routing object directly works.
|
|
364
|
+
- `createBaseSeed` now sets `_status: 'published'` on created / updated pages and posts by default. Pass `status: 'draft'` per entry to keep it as a draft.
|
|
365
|
+
|
|
366
|
+
## Building
|
|
367
|
+
|
|
368
|
+
```bash
|
|
369
|
+
bun install
|
|
370
|
+
bun run build # produces dist/ via bunup
|
|
371
|
+
bun run typecheck # tsc --noEmit
|
|
372
|
+
bun run test # vitest run
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
The lib is built with the same `bunup` + `exports` plugin pattern as
|
|
376
|
+
the monorepo's other plugins. One shim file per subpath under
|
|
377
|
+
`src/exports/`, each re-exports from the implementation.
|
|
378
|
+
|
|
379
|
+
## License
|
|
380
|
+
|
|
381
|
+
MIT
|
package/dist/access.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Access } from "payload";
|
|
2
|
+
declare const anyone: Access;
|
|
3
|
+
declare const authenticated: Access;
|
|
4
|
+
declare const authenticatedOrPublished: Access;
|
|
5
|
+
import { Access as Access_wc6ft0 } from "payload";
|
|
6
|
+
declare const _default: {
|
|
7
|
+
anyone: Access_wc6ft0;
|
|
8
|
+
authenticated: Access_wc6ft0;
|
|
9
|
+
authenticatedOrPublished: Access_wc6ft0;
|
|
10
|
+
};
|
|
11
|
+
export { _default as default, authenticatedOrPublished, authenticated, anyone };
|
package/dist/access.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __returnValue = (v) => v;
|
|
4
|
+
function __exportSetter(name, newValue) {
|
|
5
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
6
|
+
}
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, {
|
|
10
|
+
get: all[name],
|
|
11
|
+
enumerable: true,
|
|
12
|
+
configurable: true,
|
|
13
|
+
set: __exportSetter.bind(all, name)
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
17
|
+
|
|
18
|
+
// src/core/access/index.ts
|
|
19
|
+
var anyone = () => true;
|
|
20
|
+
var authenticated = ({ req: { user } }) => Boolean(user);
|
|
21
|
+
var authenticatedOrPublished = ({ req: { user } }) => {
|
|
22
|
+
if (user)
|
|
23
|
+
return true;
|
|
24
|
+
return { _status: { equals: "published" } };
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// src/exports/access.ts
|
|
28
|
+
var access_default = { anyone, authenticated, authenticatedOrPublished };
|
|
29
|
+
export {
|
|
30
|
+
access_default as default,
|
|
31
|
+
authenticatedOrPublished,
|
|
32
|
+
authenticated,
|
|
33
|
+
anyone
|
|
34
|
+
};
|
package/dist/blocks.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { FC } from "react";
|
|
2
|
+
import { ImportMap, SanitizedConfig } from "payload";
|
|
3
|
+
type RenderBlocksProps = {
|
|
4
|
+
blocks: Array<{
|
|
5
|
+
blockType: string;
|
|
6
|
+
} & Record<string, unknown>>;
|
|
7
|
+
blockProps?: Record<string, unknown>;
|
|
8
|
+
importMap: ImportMap;
|
|
9
|
+
config: SanitizedConfig;
|
|
10
|
+
locale: string;
|
|
11
|
+
searchParams?: Record<string, string | string[] | undefined>;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Render a page's `blocks` array to React. Each block's render module
|
|
15
|
+
* is resolved via Payload's generated importMap. The host registers
|
|
16
|
+
* each block in the importMap with a key like `BlockCta#default` (use
|
|
17
|
+
* `generateImportName('block', 'cta')` to build the key).
|
|
18
|
+
*
|
|
19
|
+
* Falls back gracefully: if a block's importMap path is missing or
|
|
20
|
+
* the component is not registered, the block is skipped and a
|
|
21
|
+
* `console.warn` is logged (in dev).
|
|
22
|
+
*/
|
|
23
|
+
declare const RenderBlocks: FC<RenderBlocksProps>;
|
|
24
|
+
export { RenderBlocks as default, RenderBlocksProps, RenderBlocks };
|
package/dist/blocks.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __returnValue = (v) => v;
|
|
4
|
+
function __exportSetter(name, newValue) {
|
|
5
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
6
|
+
}
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, {
|
|
10
|
+
get: all[name],
|
|
11
|
+
enumerable: true,
|
|
12
|
+
configurable: true,
|
|
13
|
+
set: __exportSetter.bind(all, name)
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
17
|
+
|
|
18
|
+
// src/core/utils/getFromImportMap.ts
|
|
19
|
+
function getFromImportMap(key, importMap) {
|
|
20
|
+
return importMap[key.includes("#") ? key : key + "#default"];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// src/core/utils/generateImportName.ts
|
|
24
|
+
function generateImportName(type, slug) {
|
|
25
|
+
switch (type) {
|
|
26
|
+
case "block":
|
|
27
|
+
return `Block${slug.replace(/(^\w|-\w)/g, (m) => m.replace("-", "").toUpperCase())}#default`;
|
|
28
|
+
case "page":
|
|
29
|
+
return `Page${slug.replace(/(^\w|-\w)/g, (m) => m.replace("-", "").toUpperCase())}#default`;
|
|
30
|
+
default:
|
|
31
|
+
throw new Error(`Unknown type: ${type}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// src/render/blocks/renderBlocks.tsx
|
|
36
|
+
import { jsx, Fragment } from "react/jsx-runtime";
|
|
37
|
+
var RenderBlocks = ({
|
|
38
|
+
blocks,
|
|
39
|
+
blockProps,
|
|
40
|
+
config,
|
|
41
|
+
importMap,
|
|
42
|
+
locale,
|
|
43
|
+
searchParams
|
|
44
|
+
}) => {
|
|
45
|
+
if (!blocks || !Array.isArray(blocks) || blocks.length === 0)
|
|
46
|
+
return null;
|
|
47
|
+
const rendered = [];
|
|
48
|
+
for (let i = 0;i < blocks.length; i++) {
|
|
49
|
+
const block = blocks[i];
|
|
50
|
+
const { blockType } = block;
|
|
51
|
+
const importMapPath = config.admin?.dependencies?.[blockType]?.path ?? generateImportName("block", blockType);
|
|
52
|
+
const Block = getFromImportMap(importMapPath, importMap);
|
|
53
|
+
if (!Block) {
|
|
54
|
+
console.warn(`No block found for type: ${blockType}, config.admin?.dependencies?.[blockType]: ${config.admin?.dependencies?.[blockType]}`);
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
rendered.push(/* @__PURE__ */ jsx(Block, {
|
|
58
|
+
index: i,
|
|
59
|
+
...blockProps,
|
|
60
|
+
...block,
|
|
61
|
+
locale,
|
|
62
|
+
searchParams
|
|
63
|
+
}, i));
|
|
64
|
+
}
|
|
65
|
+
return /* @__PURE__ */ jsx(Fragment, {
|
|
66
|
+
children: rendered
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// src/exports/blocks.ts
|
|
71
|
+
var blocks_default = RenderBlocks;
|
|
72
|
+
export {
|
|
73
|
+
blocks_default as default,
|
|
74
|
+
RenderBlocks
|
|
75
|
+
};
|