UNPKG

@craftercms/studio-ui

Version:

Services, components, models & utils to build CrafterCMS authoring extensions.

364 lines (362 loc) 11.7 kB
/* * 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 MenuItem from '@mui/material/MenuItem'; import MenuList from '@mui/material/MenuList'; import EmptyState from '../EmptyState/EmptyState'; import { FormattedMessage } from 'react-intl'; import Typography from '@mui/material/Typography'; import ItemDisplay from '../ItemDisplay'; import ItemStateIcon from '../ItemStateIcon/ItemStateIcon'; import { getItemPublishingTargetText, getItemStateText, isInWorkflow } from '../ItemDisplay/utils'; import React from 'react'; import { makeStyles } from 'tss-react/mui'; import Popover from '@mui/material/Popover'; import palette from '../../styles/palette'; import Skeleton from '@mui/material/Skeleton'; import ItemPublishingTargetIcon from '../ItemPublishingTargetIcon/ItemPublishingTargetIcon'; import useUnmount from '../../hooks/useUnmount'; const useStyles = makeStyles()( ( theme, { root, mainItem, actionsContainer, actionsColumn, emptyRoot, itemsList, itemInfo, itemInfoContentType, itemEdited, itemEditedText, itemState, infoItem, menuItem, itemDisplayRoot, itemTypeIcon, itemTypography, icon } = {} ) => ({ root: { maxWidth: 400, borderRadius: '12px', ...root }, mainItem: { padding: '10px 20px', ...mainItem }, actionsContainer: { display: 'flex', flexDirection: 'row', padding: '10px', ...actionsContainer }, actionsColumn: { display: 'flex', flexDirection: 'column', flexBasis: '100%', flex: '1', '&:first-child': { marginRight: '60px' }, ...actionsColumn }, emptyRoot: { display: 'block', padding: '10px', textAlign: 'center', ...emptyRoot }, itemsList: { padding: 0, ...itemsList }, itemInfo: { display: 'block', borderBottom: `1px solid ${palette.gray.light4}`, ...itemInfo }, itemInfoContentType: { color: theme.palette.text.secondary, marginBottom: '4px', ...itemInfoContentType }, itemEdited: { paddingTop: '12px', borderTop: `1px solid ${palette.gray.light4}`, ...itemEdited }, itemEditedText: { color: theme.palette.text.secondary, fontWeight: 600, ...itemEditedText }, itemState: { '&> *': { marginRight: '5px' }, ...itemState }, infoItem: { cursor: 'default', backgroundColor: 'inherit !important', '&:hover': { backgroundColor: 'inherit' }, ...infoItem }, menuItem: { minWidth: '100px', ...menuItem }, itemDisplayRoot: { marginBottom: 5, ...itemDisplayRoot }, itemTypeIcon: { color: palette.teal.main, marginRight: '2px', ...itemTypeIcon }, itemTypography: { color: theme.palette.text.primary, ...itemTypography }, icon: { fontSize: '0.8rem', verticalAlign: 'middle', ...icon } }) ); export function ItemMegaMenuUI(props) { const { open, styles, item, isLoading = false, numOfLoaderItems = 5, options, editorialOptions, nonEditorialOptions, anchorEl, anchorOrigin, anchorReference, anchorPosition, contentType, locale, onClose, onClosed, onMenuItemClicked, classes: propClasses } = props; const { classes, cx } = useStyles(styles); const isFolder = item?.systemType === 'folder'; const inWorkflow = isInWorkflow(item?.stateMap); return React.createElement( Popover, { open: open, onClose: onClose, anchorEl: anchorEl, anchorOrigin: anchorOrigin, anchorReference: anchorReference, anchorPosition: anchorPosition, classes: { paper: classes.root, ...propClasses } }, React.createElement( 'section', { className: cx(classes.itemInfo, classes.infoItem, classes.mainItem) }, React.createElement( Typography, { variant: 'body2', className: classes.itemInfoContentType }, isLoading ? React.createElement(Skeleton, { animation: 'wave' }) : contentType ), isLoading ? React.createElement(Skeleton, { animation: 'wave' }) : React.createElement(ItemDisplay, { item: item, labelComponent: 'h2', showPublishingTarget: false, showWorkflowState: false, classes: { root: classes.itemDisplayRoot, icon: classes.itemTypeIcon }, labelTypographyProps: { className: classes.itemTypography } }), isLoading ? React.createElement(Skeleton, { animation: 'wave' }) : React.createElement( 'div', { className: classes.itemState }, !isFolder && (inWorkflow ? React.createElement( React.Fragment, null, React.createElement(ItemStateIcon, { item: item, className: classes.icon }), React.createElement( Typography, { variant: 'body2', component: 'span' }, getItemStateText(item?.stateMap, { user: item?.lockOwner?.username }) ) ) : React.createElement( React.Fragment, null, React.createElement(ItemPublishingTargetIcon, { item: item, className: classes.icon }), React.createElement( Typography, { variant: 'body2', component: 'span' }, getItemPublishingTargetText(item?.stateMap) ) )) ) ), isLoading ? React.createElement( 'div', { className: cx(classes.actionsContainer) }, new Array(2).fill(null).map((value, i) => React.createElement( MenuList, { key: i, className: cx(classes.actionsColumn, classes.itemsList) }, new Array(Math.ceil(numOfLoaderItems / 2)) .fill(null) .map((value, j) => React.createElement( MenuItem, { key: j, className: cx(classes.menuItem, propClasses?.menuItem) }, React.createElement(Skeleton, { animation: 'wave', width: '100%' }) ) ) ) ) ) : options.flatMap((i) => i).length === 0 ? React.createElement(EmptyState, { title: React.createElement(FormattedMessage, { id: 'contextMenu.emptyOptionsMessage', defaultMessage: 'No options available to display.' }) }) : React.createElement( 'div', { className: cx(classes.actionsContainer) }, React.createElement( MenuList, { className: cx(classes.actionsColumn, classes.itemsList) }, editorialOptions.map((option, y) => React.createElement(MenuItem, { dense: true, autoFocus: y === 0, key: option.id, onClick: (e) => onMenuItemClicked(option.id, e), className: cx(classes.menuItem, propClasses?.menuItem), children: option.label }) ) ), React.createElement( 'div', { className: classes.actionsColumn }, nonEditorialOptions.map((section, i) => React.createElement( MenuList, { key: i, className: classes.itemsList }, section.map((option, y) => React.createElement(MenuItem, { dense: true, key: option.id, divider: i !== nonEditorialOptions.length - 1 && y === section.length - 1, onClick: (e) => onMenuItemClicked(option.id, e), className: cx(classes.menuItem, propClasses?.menuItem), children: option.label }) ) ) ) ) ), React.createElement( 'section', { className: cx(classes.itemEdited, classes.infoItem, classes.mainItem) }, isLoading ? React.createElement(Skeleton, { animation: 'wave', width: '100%' }) : React.createElement( React.Fragment, null, React.createElement( Typography, { variant: 'body2', color: 'text.secondary', title: item.path, noWrap: true }, item.path ), React.createElement( Typography, { variant: 'body2' }, React.createElement(FormattedMessage, { id: 'itemMegaMenu.editedBy', defaultMessage: '{edited} {date} {byLabel} {by}', values: { date: new Intl.DateTimeFormat(locale.localeCode, locale.dateTimeFormatOptions).format( new Date(item?.sandbox.dateModified) ), by: item?.sandbox.modifier?.username ?? '', edited: React.createElement( 'span', { className: classes.itemEditedText }, React.createElement(FormattedMessage, { id: 'words.edited', defaultMessage: 'Edited' }) ), byLabel: item?.sandbox.modifier?.username ? React.createElement( 'span', { className: classes.itemEditedText }, React.createElement(FormattedMessage, { id: 'words.by', defaultMessage: 'By' }) ) : '' } }) ) ) ), React.createElement(Unmount, { onClosed: onClosed }) ); } function Unmount(props) { useUnmount(props.onClosed); return null; } export default ItemMegaMenuUI;