-
-
Notifications
You must be signed in to change notification settings - Fork 68
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Re-designed CTA card settings panel components (#1451)
ref https://linear.app/ghost/issue/PLG-355/improve-cta-card-settings-panel - Updated ButtonGroup styles. - Added a button-style image upload placeholder to MediaPlaceholder. Also updated the VideoCard to follow the same style. - Refactored ColorOptionButtons and ColorPicker to display swatches and colorpicker inside toolbar. This also affects the callout, signup and header cards and the image-background selector. - Added pink and purple as background colors to the CTA card. - Changed CTA card link styles to currentColor instead of accent color – both for the label and the body text. - Extracted modified UI components to beta copies to limit impact and allow easier migration of production cards to new settings UI components later on --------- Co-authored-by: Sanne de Vries <[email protected]> Co-authored-by: Kevin Ansfield <[email protected]>
- Loading branch information
1 parent
1a3874f
commit 1915539
Showing
25 changed files
with
1,249 additions
and
107 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
64 changes: 64 additions & 0 deletions
64
packages/koenig-lexical/src/components/ui/ButtonGroupBeta.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import PropTypes from 'prop-types'; | ||
import React from 'react'; | ||
|
||
import {Tooltip} from './Tooltip'; | ||
import {usePreviousFocus} from '../../hooks/usePreviousFocus'; | ||
|
||
export function ButtonGroupBeta({buttons = [], selectedName, onClick, hasTooltip = true}) { | ||
return ( | ||
<div className="flex"> | ||
<ul className="flex items-center justify-evenly rounded-lg bg-grey-100 font-sans text-md font-normal text-white" role="menubar"> | ||
{buttons.map(({label, name, Icon, dataTestId, ariaLabel}) => ( | ||
<ButtonGroupIconButton | ||
key={`${name}-${label}`} | ||
ariaLabel={ariaLabel} | ||
dataTestId={dataTestId} | ||
hasTooltip={hasTooltip} | ||
Icon={Icon} | ||
label={label} | ||
name={name} | ||
selectedName={selectedName} | ||
onClick={onClick} | ||
/> | ||
))} | ||
</ul> | ||
</div> | ||
); | ||
} | ||
|
||
export function ButtonGroupIconButton({dataTestId, onClick, label, ariaLabel, name, selectedName, Icon, hasTooltip}) { | ||
const isActive = name === selectedName; | ||
|
||
const {handleMousedown, handleClick} = usePreviousFocus(onClick, name); | ||
|
||
return ( | ||
<li className="mb-0"> | ||
<button | ||
aria-checked={isActive} | ||
aria-label={ariaLabel || label} | ||
className={`group relative flex h-7 w-8 cursor-pointer items-center justify-center rounded-lg text-black dark:text-white dark:hover:bg-grey-900 ${isActive ? 'border border-grey-300 bg-white shadow-xs dark:bg-grey-900' : '' } ${Icon ? '' : 'text-[1.3rem] font-bold'}`} | ||
data-testid={dataTestId} | ||
role="menuitemradio" | ||
type="button" | ||
onClick={handleClick} | ||
onMouseDown={handleMousedown} | ||
> | ||
{Icon ? <Icon className="size-4 stroke-2" /> : label} | ||
{(Icon && label && hasTooltip) && <Tooltip label={label} />} | ||
</button> | ||
</li> | ||
); | ||
} | ||
|
||
ButtonGroupBeta.propTypes = { | ||
selectedName: PropTypes.oneOf(['regular', 'wide', 'full', 'split', 'center', 'left', 'small', 'medium', 'large', 'grid', 'list', 'minimal', 'immersive']).isRequired, | ||
hasTooltip: PropTypes.bool, | ||
onClick: PropTypes.func.isRequired, | ||
buttons: PropTypes.arrayOf(PropTypes.shape({ | ||
label: PropTypes.string, | ||
name: PropTypes.string.isRequired, | ||
Icon: PropTypes.elementType, | ||
dataTestId: PropTypes.string, | ||
ariaLabel: PropTypes.string | ||
})) | ||
}; |
48 changes: 48 additions & 0 deletions
48
packages/koenig-lexical/src/components/ui/ButtonGroupBeta.stories.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import ImgFullIcon from '../../assets/icons/kg-img-full.svg?react'; | ||
import ImgRegularIcon from '../../assets/icons/kg-img-regular.svg?react'; | ||
import ImgWideIcon from '../../assets/icons/kg-img-wide.svg?react'; | ||
import React from 'react'; | ||
import {ButtonGroupBeta, ButtonGroupIconButton} from './ButtonGroupBeta'; | ||
|
||
const story = { | ||
title: 'Generic/Button group (beta)', | ||
component: ButtonGroupBeta, | ||
subcomponents: {ButtonGroupIconButton}, | ||
parameters: { | ||
status: { | ||
type: 'functional' | ||
} | ||
}, | ||
argTypes: { | ||
selectedName: {control: 'select', options: ['regular', 'wide', 'full']} | ||
} | ||
}; | ||
export default story; | ||
|
||
const Template = (args) => { | ||
return ( | ||
<ButtonGroupBeta {...args} /> | ||
); | ||
}; | ||
|
||
export const CardWidth = Template.bind({}); | ||
CardWidth.args = { | ||
selectedName: 'regular', | ||
buttons: [ | ||
{ | ||
label: 'Regular', | ||
name: 'regular', | ||
Icon: ImgRegularIcon | ||
}, | ||
{ | ||
label: 'Wide', | ||
name: 'wide', | ||
Icon: ImgWideIcon | ||
}, | ||
{ | ||
label: 'Full', | ||
name: 'full', | ||
Icon: ImgFullIcon | ||
} | ||
] | ||
}; |
93 changes: 93 additions & 0 deletions
93
packages/koenig-lexical/src/components/ui/ColorOptionButtonsBeta.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import PlusIcon from '../../assets/icons/plus.svg?react'; | ||
import React, {useState} from 'react'; | ||
import {Tooltip} from './Tooltip'; | ||
import {useClickOutside} from '../../hooks/useClickOutside'; | ||
import {usePreviousFocus} from '../../hooks/usePreviousFocus'; | ||
|
||
export function ColorOptionButtonsBeta({buttons = [], selectedName, onClick}) { | ||
const [isOpen, setIsOpen] = useState(false); | ||
const componentRef = React.useRef(null); | ||
|
||
const selectedButton = buttons.find(button => button.name === selectedName); | ||
|
||
// Close the swatch popover when clicking outside of it | ||
useClickOutside(isOpen, componentRef, () => setIsOpen(false)); | ||
|
||
return ( | ||
<div ref={componentRef} className="relative"> | ||
<button | ||
className={`relative size-6 cursor-pointer rounded-full ${selectedName ? 'p-[2px]' : 'border border-grey-200 dark:border-grey-800'}`} | ||
data-testid="color-options-button" | ||
type="button" | ||
onClick={() => setIsOpen(!isOpen)} | ||
> | ||
{selectedName && ( | ||
<div className="absolute inset-0 rounded-full bg-clip-content p-[3px]" style={{ | ||
background: 'conic-gradient(hsl(360,100%,50%),hsl(315,100%,50%),hsl(270,100%,50%),hsl(225,100%,50%),hsl(180,100%,50%),hsl(135,100%,50%),hsl(90,100%,50%),hsl(45,100%,50%),hsl(0,100%,50%))', | ||
WebkitMask: 'linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)', | ||
WebkitMaskComposite: 'xor', | ||
mask: 'linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)', | ||
maskComposite: 'exclude' | ||
}} /> | ||
)} | ||
<span | ||
className={`${selectedButton?.color || ''} block size-full rounded-full border-2 border-white`} | ||
></span> | ||
</button> | ||
|
||
{/* Color options popover */} | ||
{isOpen && ( | ||
<div className="absolute -right-3 bottom-full z-10 mb-2 rounded-lg bg-white px-3 py-2 shadow" data-testid="color-options-popover"> | ||
<div className="flex"> | ||
<ul className="flex w-full items-center justify-between rounded-md font-sans text-md font-normal text-white"> | ||
{buttons.map(({label, name, color}) => ( | ||
name !== 'image' ? | ||
<ColorButton | ||
key={`${name}-${label}`} | ||
color={color} | ||
data-testid={`color-options-${name}-button`} | ||
label={label} | ||
name={name} | ||
selectedName={selectedName} | ||
onClick={(title) => { | ||
onClick(title); | ||
setIsOpen(false); | ||
}} | ||
/> | ||
: | ||
<li key='background-image' className={`mb-0 flex size-[3rem] cursor-pointer items-center justify-center rounded-full border-2 ${selectedName === name ? 'border-green' : 'border-transparent'}`} data-testid="background-image-color-button" type="button" onClick={() => onClick(name)}> | ||
<span className="border-1 flex size-6 items-center justify-center rounded-full border border-black/5"> | ||
<PlusIcon className="size-3 stroke-grey-700 stroke-2 dark:stroke-grey-500 dark:group-hover:stroke-grey-100" /> | ||
</span> | ||
</li> | ||
))} | ||
</ul> | ||
</div> | ||
</div> | ||
)} | ||
</div> | ||
); | ||
} | ||
|
||
export function ColorButton({onClick, label, name, color, selectedName}) { | ||
const isActive = name === selectedName; | ||
|
||
const {handleMousedown, handleClick} = usePreviousFocus(onClick, name); | ||
return ( | ||
<li className="mb-0"> | ||
<button | ||
aria-label={label} | ||
className={`group relative flex size-6 cursor-pointer items-center justify-center rounded-full border-2 ${isActive ? 'border-green' : 'border-transparent'}`} | ||
data-test-id={`color-picker-${name}`} | ||
type="button" | ||
onClick={handleClick} | ||
onMouseDown={handleMousedown} | ||
> | ||
<span | ||
className={`${color} size-[1.8rem] rounded-full border`} | ||
></span> | ||
<Tooltip label={label} /> | ||
</button> | ||
</li> | ||
); | ||
} |
Oops, something went wrong.