0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-03-11 02:12:21 -05:00

Fixed minor AdminX logic issues (#18209)

refs https://github.com/TryGhost/Product/issues/3832

---

### <samp>🤖 Generated by Copilot at fd2a023</samp>

This pull request improves the UI and UX of the admin settings app by
fixing some bugs, enhancing some components, and adding some logic to
handle different feature states. It affects the `ColorPickerField`,
`Toggle`, `EnableNewsletters`, `TierDetailModal`, `Modal`, and
`DefaultRecipients` components, as well as the files
`ColorPickerField.tsx`, `Toggle.tsx`, `EnableNewsletters.tsx`,
`TierDetailModal.tsx`, `Modal.tsx`, and `DefaultRecipients.tsx`.
This commit is contained in:
Jono M 2023-09-19 08:56:11 +01:00 committed by GitHub
parent 530492635f
commit bd013ed18c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 43 additions and 9 deletions

View file

@ -9,6 +9,14 @@ const ColorPickerContext = createContext<{colorPickers: Array<{ id: string; setE
colorPickers: []
});
const to6DigitHex = (hex: string) => {
if (hex.length === 4) {
return hex.replace(/#(.)(.)(.)/, '#$1$1$2$2$3$3');
} else {
return hex;
}
};
const ColorPickerField = ({testId, title, direction, value, hint, error, eyedropper, clearButtonValue, onChange, swatches = [], alwaysOpen = false, debounceMs}: {
testId?: string;
title?: ReactNode;
@ -29,7 +37,15 @@ const ColorPickerField = ({testId, title, direction, value, hint, error, eyedrop
const id = useId();
useEffect(() => {
setLocalValue(value);
setLocalValue((currentValue) => {
// If the current value is the 3-digit equivalent of the new value,
// the user probably typed it as 3 digits so keep showing it that way in the UI
if (to6DigitHex(currentValue || '') === value) {
return currentValue;
}
return value;
});
}, [value]);
useEffect(() => {
@ -66,7 +82,7 @@ const ColorPickerField = ({testId, title, direction, value, hint, error, eyedrop
const handleChange = (newValue: string | null) => {
setLocalValue(newValue);
debouncedOnChange?.(newValue);
debouncedOnChange?.(newValue ? to6DigitHex(newValue) : null);
};
let content = (

View file

@ -32,6 +32,7 @@ const Toggle: React.FC<ToggleProps> = ({
separator,
error,
checked,
disabled,
onChange
}) => {
const id = useId();
@ -83,7 +84,16 @@ const Toggle: React.FC<ToggleProps> = ({
<div>
<div className={`group flex items-start gap-2 dark:text-white ${direction === 'rtl' && 'justify-between'} ${separator && 'pb-2'}`}>
<input checked={checked}
className={`${toggleBgClass} appearance-none rounded-full bg-grey-300 transition after:absolute after:ml-0.5 after:mt-0.5 after:rounded-full after:border-none after:bg-white after:transition-[background-color_0.2s,transform_0.2s] after:content-[''] checked:after:absolute checked:after:rounded-full checked:after:border-none checked:after:bg-white checked:after:transition-[background-color_0.2s,transform_0.2s] checked:after:content-[''] hover:cursor-pointer group-hover:opacity-80 dark:bg-grey-800 ${sizeStyles} ${direction === 'rtl' && ' order-2'}`}
className={clsx(
toggleBgClass,
'appearance-none rounded-full bg-grey-300 transition dark:bg-grey-800',
`after:absolute after:ml-0.5 after:mt-0.5 after:rounded-full after:border-none after:bg-white after:transition-[background-color_0.2s,transform_0.2s] after:content-['']`,
`checked:after:absolute checked:after:rounded-full checked:after:border-none checked:after:bg-white checked:after:transition-[background-color_0.2s,transform_0.2s] checked:after:content-['']`,
'enabled:hover:cursor-pointer disabled:opacity-40 enabled:group-hover:opacity-80',
sizeStyles,
direction === 'rtl' && ' order-2'
)}
disabled={disabled}
id={id}
role="switch"
type="checkbox"

View file

@ -260,7 +260,7 @@ const Modal: React.FC<ModalProps> = ({
);
return (
<div className={backdropClasses} id='modal-backdrop' onClick={handleBackdropClick}>
<div className={backdropClasses} id='modal-backdrop' onMouseDown={handleBackdropClick}>
<div className={clsx(
'pointer-events-none fixed inset-0 z-0',
(backDrop && !formSheet) && topLevelBackdropClasses,

View file

@ -120,7 +120,7 @@ const DefaultRecipients: React.FC<{ keywords: string[] }> = ({keywords}) => {
},
{
label: 'Active Tiers',
options: tiers?.filter(({active}) => active).map(tier => ({value: tier.id, label: tier.name, color: 'black'})) || []
options: tiers?.filter(({active, type}) => active && type !== 'free').map(tier => ({value: tier.id, label: tier.name, color: 'black'})) || []
},
{
label: 'Archived Tiers',

View file

@ -10,7 +10,9 @@ const EnableNewsletters: React.FC<{ keywords: string[] }> = ({keywords}) => {
const {settings} = useGlobalData();
const {mutateAsync: editSettings} = useEditSettings();
const [newslettersEnabled] = getSettingValues(settings, ['editor_default_email_recipients']) as [string];
const [newslettersEnabled, membersSignupAccess] = getSettingValues<string>(settings, ['editor_default_email_recipients', 'members_signup_access']);
const isDisabled = membersSignupAccess === 'none';
const handleToggleChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
const updates: Setting[] = [
@ -27,8 +29,9 @@ const EnableNewsletters: React.FC<{ keywords: string[] }> = ({keywords}) => {
const enableToggle = (
<>
<Toggle
checked={newslettersEnabled !== 'disabled'}
checked={isDisabled ? false : newslettersEnabled !== 'disabled'}
direction='rtl'
disabled={isDisabled}
onChange={handleToggleChange}
/>
</>
@ -46,7 +49,7 @@ const EnableNewsletters: React.FC<{ keywords: string[] }> = ({keywords}) => {
values={[
{
key: 'private',
value: newslettersEnabled !== 'disabled' ? (
value: (!isDisabled && newslettersEnabled !== 'disabled') ? (
<div className='flex items-center gap-2'>
<Icon colorClass='text-green' name='check' size='sm' />
<span>Enabled</span>
@ -54,7 +57,10 @@ const EnableNewsletters: React.FC<{ keywords: string[] }> = ({keywords}) => {
) : (
<div className='flex items-center gap-2 text-grey-900'>
<Icon colorClass='text-grey-600' name='mail-block' size='sm' />
<span>Disabled</span>
<span>
Disabled
{isDisabled && ' by Access settings'}
</span>
</div>
)
}

View file

@ -146,11 +146,13 @@ const TierDetailModalContent: React.FC<{tier?: Tier}> = ({tier}) => {
placeholder='Bronze'
title='Name'
value={formState.name || ''}
autoFocus
onBlur={() => validators.name()}
onChange={e => updateForm(state => ({...state, name: e.target.value}))}
/>}
<TextField
autoComplete='off'
autoFocus={isFreeTier}
placeholder={isFreeTier ? `Free preview of ${siteTitle}` : 'Full access to premium content'}
title='Description'
value={formState.description || ''}