Files
payloadcms/test/live-preview/utilities/formatLivePreviewURL.ts
Jacob Fletcher f2213e5c5c feat: mount live preview to document root (#12860)
Mounts live preview to `../:id` instead `../:id/preview`.

This is a huge win for both UX and a maintainability standpoint.

Here are just a few of those wins:

1. If you edit a document, _then_ decide you want to preview those
changes, you are currently presented with the `LeaveWithoutSaving` modal
and are forced to either save your edits or clear them. This is because
you are being navigated to an entirely new page with it's own form
context. Instead, you should be able to freely navigate back and forth
between the two.
2. If you are an editor who most often uses Live Preview, or you are
editing a collection that typically requires it, you likely want it to
automatically enter live preview mode when you open a document.
Currently, the user has to navigate to the document _first_, then use
the live preview tab. Instead, you should be able to set a preference
and avoid this extra step.
3. Since the inception of Live Preview, we've been maintaining largely
the same code across the default edit view and the live preview view,
which often became out of sync and inconsistent—but they're essentially
doing the same thing. While we could abstract a lot of this out, it is
no longer necessary if the two views are combined into one.

This change does also include some small modifications to UI. The "Live
Preview" tab no longer exists, and instead has been replaced with a
button placed next to the document controls (subject to change).

Before:


https://github.com/user-attachments/assets/48518b02-87ba-4750-ba7b-b21b5c75240a

After:


https://github.com/user-attachments/assets/a8ec8657-a6d6-4ee1-b9a7-3c1173bcfa96
2025-06-27 11:58:00 -04:00

46 lines
1.3 KiB
TypeScript

import type { LivePreviewConfig } from 'payload'
export const formatLivePreviewURL: LivePreviewConfig['url'] = async ({
data,
collectionConfig,
req,
}) => {
let baseURL = `/live-preview`
// You can run async requests here, if needed
// For example, multi-tenant apps may need to lookup additional data
if (data?.tenant) {
try {
const fullTenant = await req.payload
.find({
collection: 'tenants',
where: {
id: {
equals: data.tenant,
},
},
limit: 1,
depth: 0,
})
.then((res) => res?.docs?.[0])
if (fullTenant?.clientURL) {
// Note: appending a fully-qualified URL here won't work for preview deployments on Vercel
baseURL = `${fullTenant.clientURL}/live-preview`
}
} catch (e) {
console.error(e)
}
}
// Format the URL as needed, based on the document and data
// I.e. append '/posts' to the URL if the document is a post
// You can also do this on individual collection or global config, if preferred
const isPage = collectionConfig && collectionConfig.slug === 'pages'
const isHomePage = isPage && data?.slug === 'home'
return `${baseURL}${
!isPage && collectionConfig ? `/${collectionConfig.slug}` : ''
}${!isHomePage && data?.slug ? `/${data.slug}` : ''}`
}