@craftercms/studio-ui
Version:
Services, components, models & utils to build CrafterCMS authoring extensions.
171 lines (169 loc) • 6.17 kB
JavaScript
/*
* Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { useEffect, useState } from 'react';
import AsyncVideoPlayer from '../AsyncVideoPlayer/AsyncVideoPlayer';
import LoadingState, { ConditionalLoadingState } from '../LoadingState/LoadingState';
import IFrame from '../IFrame/IFrame';
import { nou } from '../../utils/object';
import AceEditor from '../AceEditor/AceEditor';
import { backgroundModes } from './utils';
import { useStyles } from './styles';
import DialogFooter from '../DialogFooter';
import SecondaryButton from '../SecondaryButton';
import { FormattedMessage } from 'react-intl';
import PrimaryButton from '../PrimaryButton';
import { DialogBody } from '../DialogBody';
import { useDispatch } from 'react-redux';
import { closePreviewDialog, showCodeEditorDialog } from '../../state/actions/dialogs';
import { batchActions } from '../../state/actions/misc';
import { hasEditAction, isBlobUrl } from '../../utils/content';
import { useSelection } from '../../hooks/useSelection';
import useItemsByPath from '../../hooks/useItemsByPath';
import useActiveSiteId from '../../hooks/useActiveSiteId';
import { fetchSandboxItem } from '../../state/actions/content';
import useItemsBeingFetchedByPath from '../../hooks/useItemsBeingFetchedByPath';
export function PreviewDialogContainer(props) {
const { title, content, mode, url, path, onClose, type, mimeType, backgroundModeIndex } = props;
const { classes, cx } = useStyles();
const siteId = useActiveSiteId();
const items = useItemsByPath();
const itemsBeingFetchedByPath = useItemsBeingFetchedByPath();
const item = items?.[path];
const dispatch = useDispatch();
const guestBase = useSelection((state) => state.env.guestBase);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
if (type === 'editor' && path && !items[path] && !itemsBeingFetchedByPath[path]) {
dispatch(fetchSandboxItem({ path }));
}
}, [siteId, items, path, type, dispatch, itemsBeingFetchedByPath]);
const renderPreview = () => {
switch (type) {
case 'image':
return React.createElement('img', { src: url, alt: '' });
case 'video':
return React.createElement(AsyncVideoPlayer, {
playerOptions: { src: url, autoplay: true, ...(mimeType ? { type: mimeType } : {}) }
});
case 'page':
return React.createElement(
React.Fragment,
null,
isLoading && React.createElement(LoadingState, null),
React.createElement(IFrame, {
url: url,
title: title,
width: isLoading ? 0 : 960,
height: isLoading ? 0 : 600,
onLoadComplete: () => setIsLoading(false)
})
);
case 'editor': {
return React.createElement(
ConditionalLoadingState,
{ isLoading: nou(content) },
React.createElement(AceEditor, {
value: content,
classes: { editorRoot: classes.editor },
mode: `ace/mode/${mode}`,
readOnly: true,
highlightActiveLine: false,
highlightGutterLine: false,
highlightSelectedWord: false
})
);
}
case 'pdf': {
return React.createElement(IFrame, {
url: isBlobUrl(url) ? url : `${guestBase}${url}`,
title: title,
width: '100%',
height: '100vh'
});
}
case 'audio': {
return React.createElement(
'audio',
{ controls: true, autoPlay: true },
React.createElement('source', { src: url, type: mimeType })
);
}
default:
break;
}
};
const onEdit = () => {
dispatch(
batchActions([
closePreviewDialog(),
showCodeEditorDialog({
path: url,
mode
})
])
);
};
return React.createElement(
React.Fragment,
null,
React.createElement(
DialogBody,
{
className: cx(
classes.container,
backgroundModes[backgroundModeIndex]?.mode !== 'default' &&
classes[backgroundModes[backgroundModeIndex].classKey]
),
sx: {
padding: 0
}
},
renderPreview()
),
type === 'editor' &&
React.createElement(
DialogFooter,
null,
React.createElement(
SecondaryButton,
{ onClick: (e) => onClose(e, null) },
React.createElement(FormattedMessage, { id: 'words.close', defaultMessage: 'Close' })
),
item &&
hasEditAction(item.availableActions) &&
React.createElement(
PrimaryButton,
{ sx: { marginLeft: '15px' }, onClick: onEdit },
React.createElement(FormattedMessage, { id: 'words.edit', defaultMessage: 'Edit' })
)
)
);
}