From 5caf100a13d968719f35965e20234fac6701bef0 Mon Sep 17 00:00:00 2001 From: Jessica Chowdhury Date: Fri, 1 Dec 2023 17:25:45 +0000 Subject: [PATCH] feat: add secondary actions to publish button --- .../components/elements/Button/index.scss | 37 +++++++++ .../components/elements/Button/index.tsx | 80 ++++++++++++++++--- .../admin/components/elements/Button/types.ts | 6 ++ .../elements/DocumentControls/index.scss | 12 ++- .../elements/Popup/PopupTrigger/index.tsx | 10 ++- .../components/elements/Publish/index.tsx | 29 ++++++- test/versions/collections/Drafts.ts | 10 +-- 7 files changed, 162 insertions(+), 22 deletions(-) diff --git a/packages/payload/src/admin/components/elements/Button/index.scss b/packages/payload/src/admin/components/elements/Button/index.scss index bcf2b92e13..46cc1cf11f 100644 --- a/packages/payload/src/admin/components/elements/Button/index.scss +++ b/packages/payload/src/admin/components/elements/Button/index.scss @@ -24,6 +24,10 @@ a.btn { @include color-svg(currentColor); } + &__wrap { + display: flex; + } + &--has-tooltip { position: relative; } @@ -57,6 +61,11 @@ a.btn { padding: base(0.25) base(0.5); } + &--has-secondary-actions { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } + &--style-primary { background-color: var(--theme-elevation-800); color: var(--theme-elevation-0); @@ -214,4 +223,32 @@ a.btn { outline: var(--accessibility-outline); outline-offset: var(--accessibility-outline-offset); } + + &__chevron { + @include color-svg(currentColor); + border-radius: $style-radius-m; + border-left: 1px solid var(--theme-elevation-600); + border-top-left-radius: 0; + border-bottom-left-radius: 0; + cursor: pointer; + + .icon { + vertical-align: middle; + transition: all 0.2s ease-in-out; + + & path { + stroke-width: 1px; + } + } + + &--open { + .icon { + transform: rotate(180deg); + } + } + + &:focus:not(:focus-visible) { + box-shadow: none; + } + } } diff --git a/packages/payload/src/admin/components/elements/Button/index.tsx b/packages/payload/src/admin/components/elements/Button/index.tsx index 6f1131c8b3..cb16cd032e 100644 --- a/packages/payload/src/admin/components/elements/Button/index.tsx +++ b/packages/payload/src/admin/components/elements/Button/index.tsx @@ -4,11 +4,14 @@ import { Link } from 'react-router-dom' import type { Props } from './types' import chevron from '../../icons/Chevron' +import Chevron from '../../icons/Chevron' import edit from '../../icons/Edit' import linkIcon from '../../icons/Link' import plus from '../../icons/Plus' import swap from '../../icons/Swap' import x from '../../icons/X' +import Popup from '../Popup' +import { ButtonGroup, Button as PopupButton } from '../Popup/PopupButtonList' import Tooltip from '../Tooltip' import './index.scss' @@ -46,6 +49,41 @@ const ButtonContents = ({ children, icon, showTooltip, tooltip }) => { ) } +const SecondaryActions = ({ className, secondaryActions }) => { + const [showSecondaryActions, setShowSecondaryActions] = React.useState(false) + const multipleActions = secondaryActions.length > 1 + + return ( + + + + } + buttonClassName={[ + className && className, + `${baseClass}__chevron`, + showSecondaryActions && `${baseClass}__chevron--open`, + ] + .filter(Boolean) + .join(' ')} + onToggleOpen={(active) => setShowSecondaryActions(active)} + > + + {multipleActions ? ( + secondaryActions.map((action, i) => ( + + {action.label} + + )) + ) : ( + {secondaryActions.label} + )} + + + ) +} + const Button = forwardRef((props, ref) => { const { id, @@ -61,6 +99,7 @@ const Button = forwardRef((props, newTab, onClick, round, + secondaryActions, size = 'medium', to, tooltip, @@ -82,6 +121,7 @@ const Button = forwardRef((props, size && `${baseClass}--size-${size}`, iconPosition && `${baseClass}--icon-position-${iconPosition}`, tooltip && `${baseClass}--has-tooltip`, + secondaryActions && `${baseClass}--has-secondary-actions`, ] .filter(Boolean) .join(' ') @@ -106,36 +146,50 @@ const Button = forwardRef((props, type, } + const ButtonContent = ( + + {children} + + ) + + let buttonElement + switch (el) { case 'link': - return ( + buttonElement = ( - - {children} - + {ButtonContent} ) + break case 'anchor': - return ( + buttonElement = ( }> - - {children} - + {ButtonContent} ) + break default: const Tag = el // eslint-disable-line no-case-declarations - - return ( + buttonElement = ( - - {children} - + {ButtonContent} ) + break } + + if (secondaryActions) + return ( +
+ {buttonElement} + +
+ ) + + return buttonElement }) export default Button diff --git a/packages/payload/src/admin/components/elements/Button/types.ts b/packages/payload/src/admin/components/elements/Button/types.ts index f7534005f7..c5b735b295 100644 --- a/packages/payload/src/admin/components/elements/Button/types.ts +++ b/packages/payload/src/admin/components/elements/Button/types.ts @@ -1,6 +1,11 @@ import type { ElementType, MouseEvent } from 'react' import type React from 'react' +type secondaryAction = { + label: string + onClick: (event: MouseEvent) => void +} + export type Props = { 'aria-label'?: string buttonId?: string @@ -16,6 +21,7 @@ export type Props = { newTab?: boolean onClick?: (event: MouseEvent) => void round?: boolean + secondaryActions?: secondaryAction | secondaryAction[] size?: 'medium' | 'small' to?: string tooltip?: string diff --git a/packages/payload/src/admin/components/elements/DocumentControls/index.scss b/packages/payload/src/admin/components/elements/DocumentControls/index.scss index d6de4a6e5b..1a81c65395 100644 --- a/packages/payload/src/admin/components/elements/DocumentControls/index.scss +++ b/packages/payload/src/admin/components/elements/DocumentControls/index.scss @@ -192,9 +192,19 @@ } &__controls { - padding-left: var(--gutter-h); + padding: base(0.25) 0 base(0.25) var(--gutter-h); overflow: auto; + & .popup__content { + position: fixed; + left: var(--gutter-h); + right: var(--gutter-h); + } + + & .popup__caret { + display: none; + } + // do not show scrollbar because the parent container has a static height // this container has a gradient overlay as visual indication of `overflow: scroll` &::-webkit-scrollbar { diff --git a/packages/payload/src/admin/components/elements/Popup/PopupTrigger/index.tsx b/packages/payload/src/admin/components/elements/Popup/PopupTrigger/index.tsx index f1721ef4df..289a9ba695 100644 --- a/packages/payload/src/admin/components/elements/Popup/PopupTrigger/index.tsx +++ b/packages/payload/src/admin/components/elements/Popup/PopupTrigger/index.tsx @@ -36,7 +36,15 @@ export const PopupTrigger: React.FC = (props) => { } return ( - ) diff --git a/packages/payload/src/admin/components/elements/Publish/index.tsx b/packages/payload/src/admin/components/elements/Publish/index.tsx index b199e0adff..c1db8031bb 100644 --- a/packages/payload/src/admin/components/elements/Publish/index.tsx +++ b/packages/payload/src/admin/components/elements/Publish/index.tsx @@ -1,6 +1,7 @@ import qs from 'qs' import React, { useCallback } from 'react' import { useTranslation } from 'react-i18next' +import { toast } from 'react-toastify' import { useForm, useFormModified } from '../../forms/Form/context' import FormSubmit from '../../forms/Submit' @@ -8,7 +9,6 @@ import { useConfig } from '../../utilities/Config' import { useDocumentInfo } from '../../utilities/DocumentInfo' import { useLocale } from '../../utilities/Locale' import RenderCustomComponent from '../../utilities/RenderCustomComponent' - export type CustomPublishButtonProps = React.ComponentType< DefaultPublishButtonProps & { DefaultButton: React.ComponentType @@ -30,8 +30,33 @@ const DefaultPublishButton: React.FC = ({ }) => { if (!canPublish) return null + const testAction = () => { + console.log('test') + toast.success('Published to ___ locale(s)') + } + return ( - + {label} ) diff --git a/test/versions/collections/Drafts.ts b/test/versions/collections/Drafts.ts index 8f9669004a..e0eca1dee2 100644 --- a/test/versions/collections/Drafts.ts +++ b/test/versions/collections/Drafts.ts @@ -31,11 +31,11 @@ const DraftPosts: CollectionConfig = { readVersions: ({ req: { user } }) => Boolean(user), }, admin: { - components: { - edit: { - PublishButton: CustomPublishButton, - }, - }, + // components: { + // edit: { + // PublishButton: CustomPublishButton, + // }, + // }, defaultColumns: ['title', 'description', 'createdAt', '_status'], preview: () => 'https://payloadcms.com', useAsTitle: 'title',