Skip to content

Commit 545f40f

Browse files
authored
Preview: Side panel (#2400)
* Update Preview for Side Editor * Add mention of beta * Update dev-related info + difference between plans * Fix badges color * Fix broken anchors * Fix bottom of page (usage)
1 parent 1b6981d commit 545f40f

File tree

3 files changed

+170
-13
lines changed

3 files changed

+170
-13
lines changed

docusaurus/docs/cms/features/preview.md

Lines changed: 164 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,11 @@ With the Preview feature, you can preview your front end application directly fr
4040

4141
```bash
4242
CLIENT_URL=https://your-frontend-app.com
43-
PREVIEW_SECRET=your-secret-key # optional, required with Next.js draft mode
43+
PREVIEW_SECRET=your-secret-key
4444
```
4545

46+
The `PREVIEW_SECRET` key is optional but required with Next.js draft mode.
47+
4648
* A front-end application for your Strapi project should be already created and set up.
4749
:::
4850

@@ -99,7 +101,7 @@ preview: {
99101
//
100102
```
101103

102-
An example of [URL generation logic](#2-add-url-generation-logic) in given in the following basic implementation guide.
104+
An example of [URL generation logic](#2-add-url-generation) in given in the following basic implementation guide.
103105

104106
##### Previewing draft entries
105107

@@ -122,13 +124,13 @@ async handler(uid, { documentId, locale, status }) {
122124
},
123125
```
124126

125-
A more detailed example using the draft mode of Next.js is given in the [basic implementation guide](#3-add-handler-logic).
127+
A more detailed example using the draft mode of Next.js is given in the [basic implementation guide](#3-add-handler).
126128

127129
### Basic implementation guide
128130

129131
Follow these steps to add Preview capabilities to your content types.
130132

131-
#### 1. Create the Preview configuration
133+
#### 1. [Strapi] Create the Preview configuration {#1-create-config}
132134

133135
Create a new file `/config/admin.ts` (or update it if it exists) with the following basic structure:
134136

@@ -148,7 +150,7 @@ export default ({ env }) => ({
148150
});
149151
```
150152

151-
#### 2. Add URL generation logic
153+
#### 2. [Strapi] Add URL generation logic {#2-add-url-generation}
152154

153155
Add the URL generation logic with a `getPreviewPathname` function. The following example is taken from the <ExternalLink to="https://github.com/strapi/LaunchPad/tree/feat/preview" text="Launchpad"/> Strapi demo application:
154156

@@ -198,7 +200,7 @@ const getPreviewPathname = (uid, { locale, document }): string => {
198200
Some content types don't need to have a preview if it doesn't make sense, hence the default case returning `null`. A Global single type with some site metadata, for example, will not have a matching front-end page. In these cases, the handler function should return `null`, and the preview UI will not be shown in the admin panel. This is how you enable or disable preview per content type.
199201
:::
200202

201-
#### 3. Add handler logic
203+
#### 3. [Strapi] Add handler logic {#3-add-handler}
202204

203205
Create the complete configuration, expanding the basic configuration created in step 1. with the URL generation logic created in step 2., adding an appropriate handler logic:
204206

@@ -246,7 +248,7 @@ export default ({ env }) => {
246248
};
247249

248250
```
249-
#### 4. Set up the front-end preview route
251+
#### 4. [Front end] Set up the front-end preview route {#4-setup-frontend-route}
250252

251253
Setting up the front-end preview route is highly dependent on the framework used for your front-end application.
252254

@@ -285,33 +287,182 @@ export async function GET(request: Request) {
285287
}
286288
```
287289

288-
#### 5. Allow the front-end to be embedded
290+
#### 5. [Front end] Allow the front-end to be embedded {#5-allow-frontend-embed}
289291

290292
On the Strapi side, [the `allowedOrigins` configuration parameter](#allowed-origins) allows the admin panel to load the front-end window in an iframe. But allowing the embedding works both ways, so on the front-end side, you also need to allow the window to be embedded in Strapi's admin panel.
291293

292294
This requires the front-end application to have its own header directive, the CSP `frame-ancestors` directive. Setting this directive up depends on how your website is built. For instance, setting this up in Next.js requires a middleware configuration (see <ExternalLink to="https://nextjs.org/docs/app/building-your-application/configuring/content-security-policy" text="Next.js docs"/>).
293295

296+
#### 6. [Front end] Detect changes in Strapi and refresh the front-end {#6-refresh-frontend}
297+
298+
Strapi emits a `strapiUpdate` message to inform the front end that data has changed.
299+
300+
To track this, within your front-end application, add an event listener to listen to events posted through [the `postMessage()` API](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) on the `window` object. The listener needs to filter through messages and react only to Strapi-initiated messages, then refresh the iframe content.
301+
302+
With Next.js, the recommended way to refresh the iframe content is with <ExternalLink to="https://nextjs.org/docs/app/building-your-application/caching#routerrefresh" text="the `router.refresh()` method" />.
303+
304+
<Tabs groupId="js-ts">
305+
<TabItem value="js" label="JavaScript" >
306+
307+
```tsx title="next/app/path/to/your/front/end/logic.jsx" {6-17}
308+
export default function MyClientComponent({...props}) {
309+
//
310+
const router = useRouter();
311+
312+
useEffect(() => {
313+
const handleMessage = async (message) => {
314+
if (
315+
// Filters events emitted through the postMessage() API
316+
message.origin === process.env.NEXT_PUBLIC_API_URL &&
317+
message.data.type === "strapiUpdate"
318+
) { // Recommended way to refresh with Next.js
319+
router.refresh();
320+
}
321+
};
322+
323+
// Add the event listener
324+
window.addEventListener("message", handleMessage);
325+
326+
// Cleanup the event listener on unmount
327+
return () => {
328+
window.removeEventListener("message", handleMessage);
329+
};
330+
}, [router]);
331+
332+
// ...
333+
}
334+
```
335+
336+
</TabItem>
337+
<TabItem value="ts" label="TypeScript" >
338+
339+
```tsx title="next/app/path/to/your/front/end/logic.tsx" {6-17}
340+
export default function MyClientComponent({
341+
//
342+
const router = useRouter();
343+
344+
useEffect(() => {
345+
const handleMessage = async (message: MessageEvent<any>) => {
346+
if (
347+
// Filters events emitted through the postMessage() API
348+
message.origin === process.env.NEXT_PUBLIC_API_URL &&
349+
message.data.type === "strapiUpdate"
350+
) { // Recommended way to refresh with Next.js
351+
router.refresh();
352+
}
353+
};
354+
355+
// Add the event listener
356+
window.addEventListener("message", handleMessage);
357+
358+
// Cleanup the event listener on unmount
359+
return () => {
360+
window.removeEventListener("message", handleMessage);
361+
};
362+
}, [router]);
363+
364+
//
365+
})
366+
```
367+
368+
</TabItem>
369+
370+
</Tabs>
371+
372+
<details>
373+
<summary>Caching in Next.js:</summary>
374+
375+
In Next.js, [cache persistence](https://nextjs.org/docs/app/building-your-application/caching) may require additional steps. You might need to invalidate the cache by making an API call from the client side to the server, where the revalidation logic will be handled. Please refer to Next.js documentation for details, for instance with the [revalidatePath() method](https://nextjs.org/docs/app/building-your-application/caching#revalidatepath).
376+
<br/>
377+
378+
</details>
379+
380+
#### [Front end] Next steps
381+
382+
Once the preview system is set up, you need to adapt your data fetching logic to handle draft content appropriately. This involves the following steps:
383+
384+
1. Create or adapt your data fetching utility to check if draft mode is enabled
385+
2. Update your API calls to include the draft status parameter when appropriate
386+
387+
The following, taken from the <ExternalLink to="https://github.com/strapi/LaunchPad/tree/feat/preview" text="Launchpad" /> Strapi demo application, is an example of how to implement draft-aware data fetching in your Next.js front-end application:
388+
389+
```typescript {8-18}
390+
import { draftMode } from "next/headers";
391+
import qs from "qs";
392+
393+
export default async function fetchContentType(
394+
contentType: string,
395+
params: Record = {}
396+
): Promise {
397+
// Check if Next.js draft mode is enabled
398+
const { isEnabled: isDraftMode } = draftMode();
399+
400+
try {
401+
const queryParams = { ...params };
402+
// Add status=draft parameter when draft mode is enabled
403+
if (isDraftMode) {
404+
queryParams.status = "draft";
405+
}
406+
407+
const url = `${baseURL}/${contentType}?${qs.stringify(queryParams)}`;
408+
const response = await fetch(url);
409+
if (!response.ok) {
410+
throw new Error(
411+
`Failed to fetch data from Strapi (url=${url}, status=${response.status})`
412+
);
413+
}
414+
return await response.json();
415+
} catch (error) {
416+
console.error("Error fetching content:", error);
417+
throw error;
418+
}
419+
}
420+
```
421+
422+
This utility method can then be used in your page components to fetch either draft or published content based on the preview state:
423+
424+
```typescript
425+
// In your page component:
426+
const pageData = await fetchContentType('api::page.page', {
427+
// Your other query parameters
428+
});
429+
```
430+
294431
## Usage
295432

296433
**Path to use the feature:** <Icon name="feather" /> Content Manager, edit view of your content type
297434

435+
:::strapi Preview with or without the side panel
436+
Based on your CMS plan, your experience with Preview will be different:
437+
- With the Free plan, Preview will be full screen only.
438+
- With the <GrowthBadge /> and <EnterpriseBadge /> plans, you can see the Preview alongside the Edit view of the Content Manager, allowing you to edit your content and previewing it simultaneously.
439+
:::
440+
298441
Once the Preview feature is properly set up, an **Open preview** button is visible on the right side of the [Content Manager's edit view](/cms/features/content-manager#overview). Clicking it will display the preview of your content as it will appear in your front-end application, but directly within Strapi's the admin panel.
299442

300443
<!-- TODO: add a dark mode GIF -->
301444
<ThemedImage
302445
alt="Previewing content"
303446
sources={{
304-
light: '/img/assets/content-manager/previewing-content.gif',
305-
dark: '/img/assets/content-manager/previewing-content.gif',
447+
light: '/img/assets/content-manager/previewing-content2.gif',
448+
dark: '/img/assets/content-manager/previewing-content2.gif',
306449
}}
307450
/>
308451

309-
From the Preview screen, you can:
452+
Once the Preview is open, you can:
310453

311454
- click the close button <Icon name="x" classes="ph-bold" /> in the upper left corner to go back to the Edit View of the Content Manager,
312455
- switch between previewing the draft and the published version (if [Draft & Publish](/cms/features/draft-and-publish) is enabled for the content-type),
313456
- and click the link icon <Icon name="link" classes="ph-bold"/> in the upper right corner to copy the preview link. Depending on the preview tab you are currently viewing, this will either copy the link to the preview of the draft or the published version.
314457

315-
:::caution
316-
When making updates to the content, first save them before clicking on Open Preview again, otherwise your latest updates will be lost. A pop up window will warn you about this behavior.
458+
Additionally, , you can:
459+
- with <GrowthBadge /> and <EnterpriseBadge /> plans, expand the side panel by clicking on the <Icon name="arrow-line-left" classes="ph-bold" /> button to make the Preview full screen,
460+
- and, with the <EnterpriseBadge /> plan, use buttons at the top right of the editor to define the assignee and stage for the [Review Workflows feature](/cms/features/review-workflows) if enabled.
461+
462+
:::info
463+
Please note that the side panel for Preview is currently in beta and only accessible if you installed strapi with the beta flag, with the following command: `npx create-strapi@beta`.
464+
:::
465+
466+
:::note
467+
In the Edit view of the Content Manager, the Open preview button will be disabled if you have unsaved changes. Save your latest changes and you should be able to preview content again.
317468
:::

docusaurus/src/scss/badge.scss

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@
163163
--custom-badge-color: white;
164164
--custom-badge-tooltip-background-color: var(--strapi-primary-100);
165165
--custom-badge-tooltip-color: var(--custom-badge-background-color);
166+
166167
}
167168

168169
&--sso {
@@ -176,6 +177,11 @@
176177
}
177178
}
178179

180+
&--growth a,
181+
&--enterprise a {
182+
color: white !important;
183+
}
184+
179185
&--pro {
180186
--custom-badge-background-color: var(--strapi-primary-600);
181187
--custom-badge-color: #fff;
916 KB
Loading

0 commit comments

Comments
 (0)