11import * as React from 'react' ;
22
3+ import { useClipboard , useNotification , useQueryParams } from '@strapi/admin/strapi-admin' ;
34import {
4- useClipboard ,
5- useHistory ,
6- useNotification ,
7- useQueryParams ,
8- } from '@strapi/admin/strapi-admin' ;
9- import { Flex , IconButton , Typography } from '@strapi/design-system' ;
5+ Box ,
6+ type BoxProps ,
7+ Flex ,
8+ IconButton ,
9+ Tabs ,
10+ Typography ,
11+ Grid ,
12+ } from '@strapi/design-system' ;
1013import { Cross , Link as LinkIcon } from '@strapi/icons' ;
1114import { stringify } from 'qs' ;
12- import { useIntl } from 'react-intl' ;
13- import { Link , type To , useNavigate } from 'react-router-dom' ;
15+ import { type MessageDescriptor , useIntl } from 'react-intl' ;
16+ import { Link } from 'react-router-dom' ;
17+ import { styled } from 'styled-components' ;
1418
1519import { DocumentStatus } from '../../pages/EditView/components/DocumentStatus' ;
1620import { getDocumentStatus } from '../../pages/EditView/EditViewPage' ;
@@ -21,39 +25,19 @@ import { usePreviewContext } from '../pages/Preview';
2125 * -----------------------------------------------------------------------------------------------*/
2226
2327const ClosePreviewButton = ( ) => {
24- const [ { query } ] = useQueryParams ( ) ;
25- const navigate = useNavigate ( ) ;
28+ const [ { query } ] = useQueryParams < {
29+ plugins ?: Record < string , unknown > ;
30+ } > ( ) ;
2631 const { formatMessage } = useIntl ( ) ;
2732
28- const canGoBack = useHistory ( 'BackButton' , ( state ) => state . canGoBack ) ;
29- const goBack = useHistory ( 'BackButton' , ( state ) => state . goBack ) ;
30- const history = useHistory ( 'BackButton' , ( state ) => state . history ) ;
31-
32- const fallbackUrl : To = {
33- pathname : '..' ,
34- search : stringify ( query , { encode : false } ) ,
35- } ;
36-
37- const handleClick = ( e : React . MouseEvent ) => {
38- /**
39- * Prevent normal link behavior. We only make it an achor for accessibility reasons.
40- * The point of this logic is to act as the browser's back button when possible, and to fallback
41- * to a link behavior to the edit view when no history is available.
42- * */
43- e . preventDefault ( ) ;
44-
45- if ( canGoBack ) {
46- goBack ( ) ;
47- } else {
48- navigate ( fallbackUrl ) ;
49- }
50- } ;
51-
5233 return (
5334 < IconButton
5435 tag = { Link }
55- to = { history . at ( - 1 ) ?? fallbackUrl }
56- onClick = { handleClick }
36+ relative = "path"
37+ to = { {
38+ pathname : '..' ,
39+ search : stringify ( { plugins : query . plugins } , { encode : false } ) ,
40+ } }
5741 label = { formatMessage ( {
5842 id : 'content-manager.preview.header.close' ,
5943 defaultMessage : 'Close preview' ,
@@ -84,6 +68,56 @@ const Status = () => {
8468 return < DocumentStatus status = { status } size = "XS" /> ;
8569} ;
8670
71+ const PreviewTabs = ( ) => {
72+ const { formatMessage } = useIntl ( ) ;
73+
74+ // URL query params
75+ const [ { query } , setQuery ] = useQueryParams < { status : 'draft' | 'published' } > ( ) ;
76+
77+ // Get status
78+ const document = usePreviewContext ( 'PreviewHeader' , ( state ) => state . document ) ;
79+ const schema = usePreviewContext ( 'PreviewHeader' , ( state ) => state . schema ) ;
80+ const meta = usePreviewContext ( 'PreviewHeader' , ( state ) => state . meta ) ;
81+ const hasDraftAndPublish = schema ?. options ?. draftAndPublish ?? false ;
82+ const documentStatus = getDocumentStatus ( document , meta ) ;
83+
84+ const handleTabChange = ( status : string ) => {
85+ if ( status === 'published' || status === 'draft' ) {
86+ setQuery ( { status } , 'push' , true ) ;
87+ }
88+ } ;
89+
90+ if ( ! hasDraftAndPublish ) {
91+ return null ;
92+ }
93+
94+ return (
95+ < >
96+ < Tabs . Root variant = "simple" value = { query . status || 'draft' } onValueChange = { handleTabChange } >
97+ < Tabs . List
98+ aria-label = { formatMessage ( {
99+ id : 'preview.tabs.label' ,
100+ defaultMessage : 'Document status' ,
101+ } ) }
102+ >
103+ < StatusTab value = "draft" >
104+ { formatMessage ( {
105+ id : 'content-manager.containers.List.draft' ,
106+ defaultMessage : 'draft' ,
107+ } ) }
108+ </ StatusTab >
109+ < StatusTab value = "published" disabled = { documentStatus === 'draft' } >
110+ { formatMessage ( {
111+ id : 'content-manager.containers.List.published' ,
112+ defaultMessage : 'published' ,
113+ } ) }
114+ </ StatusTab >
115+ </ Tabs . List >
116+ </ Tabs . Root >
117+ </ >
118+ ) ;
119+ } ;
120+
87121/* -------------------------------------------------------------------------------------------------
88122 * PreviewHeader
89123 * -----------------------------------------------------------------------------------------------*/
@@ -110,32 +144,46 @@ const PreviewHeader = () => {
110144 } ;
111145
112146 return (
113- < Flex
114- justifyContent = "space-between"
147+ < Grid . Root
148+ gap = { 3 }
149+ gridCols = { 3 }
150+ paddingLeft = { 2 }
151+ paddingRight = { 2 }
115152 background = "neutral0"
116- padding = { 2 }
117153 borderColor = "neutral150"
118154 tag = "header"
119155 >
120- < Flex gap = { 3 } >
156+ { /* Title and status */ }
157+ < Grid . Item xs = { 1 } paddingTop = { 2 } paddingBottom = { 2 } gap = { 3 } >
121158 < ClosePreviewButton />
122- < Typography tag = "h1" fontWeight = { 600 } fontSize = { 2 } >
159+ < Typography tag = "h1" fontWeight = { 600 } fontSize = { 2 } maxWidth = "200px" >
123160 { title }
124161 </ Typography >
125- < Status />
126- </ Flex >
127- < IconButton
128- type = "button"
129- label = { formatMessage ( {
130- id : 'preview.copy.label' ,
131- defaultMessage : 'Copy preview link' ,
132- } ) }
133- onClick = { handleCopyLink }
134- >
135- < LinkIcon />
136- </ IconButton >
137- </ Flex >
162+ < DocumentStatus />
163+ </ Grid . Item >
164+ { /* Tabs */ }
165+ < Grid . Item xs = { 1 } marginBottom = "-1px" alignItems = "end" margin = "auto" >
166+ < PreviewTabs />
167+ </ Grid . Item >
168+ { /* Copy link */ }
169+ < Grid . Item xs = { 1 } justifyContent = "end" paddingTop = { 2 } paddingBottom = { 2 } >
170+ < IconButton
171+ type = "button"
172+ label = { formatMessage ( {
173+ id : 'preview.copy.label' ,
174+ defaultMessage : 'Copy preview link' ,
175+ } ) }
176+ onClick = { handleCopyLink }
177+ >
178+ < LinkIcon />
179+ </ IconButton >
180+ </ Grid . Item >
181+ </ Grid . Root >
138182 ) ;
139183} ;
140184
185+ const StatusTab = styled ( Tabs . Trigger ) `
186+ text-transform: uppercase;
187+ ` ;
188+
141189export { PreviewHeader } ;
0 commit comments