mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-10 23:36:14 -05:00
Added portal icon picker in AdminX settings (#17216)
refs https://github.com/TryGhost/Product/issues/3545
This commit is contained in:
parent
3d6848f5fd
commit
b9158215ee
7 changed files with 99 additions and 6 deletions
|
@ -1,6 +1,6 @@
|
|||
import FileUpload from './FileUpload';
|
||||
import Icon from '../Icon';
|
||||
import React from 'react';
|
||||
import React, {MouseEventHandler} from 'react';
|
||||
import clsx from 'clsx';
|
||||
|
||||
type ImageFit = 'cover' | 'contain' | 'fill' | 'scale-down' | 'none';
|
||||
|
@ -25,6 +25,7 @@ interface ImageUploadProps {
|
|||
unstyled?: boolean;
|
||||
onUpload: (file: File) => void;
|
||||
onDelete: () => void;
|
||||
onImageClick?: MouseEventHandler<HTMLImageElement>;
|
||||
}
|
||||
|
||||
const ImageUpload: React.FC<ImageUploadProps> = ({
|
||||
|
@ -42,7 +43,8 @@ const ImageUpload: React.FC<ImageUploadProps> = ({
|
|||
imageBWCheckedBg = false,
|
||||
unstyled = false,
|
||||
onUpload,
|
||||
onDelete
|
||||
onDelete,
|
||||
onImageClick
|
||||
}) => {
|
||||
if (!unstyled) {
|
||||
imageContainerClassName = clsx(
|
||||
|
@ -82,7 +84,7 @@ const ImageUpload: React.FC<ImageUploadProps> = ({
|
|||
<img alt='' className={imageClassName} id={id} src={imageURL} style={{
|
||||
width: (unstyled ? '' : width || '100%'),
|
||||
height: (unstyled ? '' : height || 'auto')
|
||||
}} />
|
||||
}} onClick={onImageClick} />
|
||||
<button className={deleteButtonClassName} type='button' onClick={onDelete}>
|
||||
{deleteButtonContent}
|
||||
</button>
|
||||
|
|
4
apps/admin-x-settings/src/assets/icons/portal-icon-1.svg
Normal file
4
apps/admin-x-settings/src/assets/icons/portal-icon-1.svg
Normal file
|
@ -0,0 +1,4 @@
|
|||
<svg width="21" height="24" viewBox="0 0 21 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>portal-icon-1</title>
|
||||
<path d="M10.533 11.267a5.135 5.135 0 1 0-.001-10.27 5.135 5.135 0 0 0 .001 10.27zM1 23a9.531 9.531 0 0 1 16.274-6.741 9.532 9.532 0 0 1 2.793 6.74" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 375 B |
4
apps/admin-x-settings/src/assets/icons/portal-icon-2.svg
Normal file
4
apps/admin-x-settings/src/assets/icons/portal-icon-2.svg
Normal file
|
@ -0,0 +1,4 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>portal-icon-2</title>
|
||||
<path stroke="currentColor" stroke-width="1.5" stroke-linecap="round" d="M12.5 2v20M2 12.5h20" fill="none"/>
|
||||
</svg>
|
After Width: | Height: | Size: 233 B |
5
apps/admin-x-settings/src/assets/icons/portal-icon-3.svg
Normal file
5
apps/admin-x-settings/src/assets/icons/portal-icon-3.svg
Normal file
|
@ -0,0 +1,5 @@
|
|||
<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>portal-icon-3</title>
|
||||
<path d="M23.5 6v14.25a2.25 2.25 0 1 1-4.5 0V3c0-.398-.158-.78-.44-1.06a1.494 1.494 0 0 0-1.06-.44h-15c-.398 0-.78.158-1.06.44C1.157 2.22 1 2.601 1 3v17.25a2.25 2.25 0 0 0 2.25 2.25h18M4.75 15h10.5m-10.5 3h6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M14.5 5.25h-9a.75.75 0 0 0-.75.75v4.5c0 .414.336.75.75.75h9a.75.75 0 0 0 .75-.75V6a.75.75 0 0 0-.75-.75z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 642 B |
5
apps/admin-x-settings/src/assets/icons/portal-icon-4.svg
Normal file
5
apps/admin-x-settings/src/assets/icons/portal-icon-4.svg
Normal file
|
@ -0,0 +1,5 @@
|
|||
<svg width="24" height="18" viewBox="0 0 24 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>portal-icon-4</title>
|
||||
<path d="M21.75 1.5H2.25A1.5 1.5 0 0 0 .75 3v12a1.5 1.5 0 0 0 1.5 1.5h19.5a1.5 1.5 0 0 0 1.5-1.5V3a1.5 1.5 0 0 0-1.5-1.5zm-6.063 5.475L19.5 10.5M8.313 6.975 4.5 10.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="m22.88 2.014-9.513 6.56a2.41 2.41 0 0 1-2.734 0L1.12 2.014" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 554 B |
5
apps/admin-x-settings/src/assets/icons/portal-icon-5.svg
Normal file
5
apps/admin-x-settings/src/assets/icons/portal-icon-5.svg
Normal file
|
@ -0,0 +1,5 @@
|
|||
<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>portal-icon-5</title>
|
||||
<path d="M17.903 12.016a5.007 5.007 0 0 0-3.031-3.654m-3.835.038a5.002 5.002 0 0 0-2.879 5.85m2.282 3.046A4.975 4.975 0 0 0 13 18a4.99 4.99 0 0 0 4.12-2.167m-1.949 5.387a8.504 8.504 0 0 0 5.756-11.295m-2.316-3.31A8.474 8.474 0 0 0 13 4.5a8.461 8.461 0 0 0-5.608 2.113m-2.28 3.213a8.503 8.503 0 0 0 5.914 11.444" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
||||
<path d="M8.924 24.29c1.273.46 2.645.71 4.076.71 5.52 0 10.17-3.727 11.57-8.803M6.712 2.777A11.994 11.994 0 0 0 1 13c0 3.545 1.537 6.731 3.982 8.928m19.867-10.839C23.933 5.369 18.977 1 13 1c-.69 0-1.367.058-2.025.17" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 799 B |
|
@ -1,16 +1,66 @@
|
|||
import Form from '../../../../admin-x-ds/global/form/Form';
|
||||
import React from 'react';
|
||||
import React, {useContext, useState} from 'react';
|
||||
import Select from '../../../../admin-x-ds/global/form/Select';
|
||||
import TextField from '../../../../admin-x-ds/global/form/TextField';
|
||||
import Toggle from '../../../../admin-x-ds/global/form/Toggle';
|
||||
import {Setting, SettingValue} from '../../../../types/api';
|
||||
import {getSettingValues} from '../../../../utils/helpers';
|
||||
|
||||
import ImageUpload from '../../../../admin-x-ds/global/form/ImageUpload';
|
||||
import clsx from 'clsx';
|
||||
import {ReactComponent as PortalIcon1} from '../../../../assets/icons/portal-icon-1.svg';
|
||||
import {ReactComponent as PortalIcon2} from '../../../../assets/icons/portal-icon-2.svg';
|
||||
import {ReactComponent as PortalIcon3} from '../../../../assets/icons/portal-icon-3.svg';
|
||||
import {ReactComponent as PortalIcon4} from '../../../../assets/icons/portal-icon-4.svg';
|
||||
import {ReactComponent as PortalIcon5} from '../../../../assets/icons/portal-icon-5.svg';
|
||||
import {ServicesContext} from '../../../providers/ServiceProvider';
|
||||
|
||||
const defaultButtonIcons = [
|
||||
{
|
||||
Component: PortalIcon1,
|
||||
value: 'icon-1'
|
||||
},
|
||||
{
|
||||
Component: PortalIcon2,
|
||||
value: 'icon-2'
|
||||
},
|
||||
{
|
||||
Component: PortalIcon3,
|
||||
value: 'icon-3'
|
||||
},
|
||||
{
|
||||
Component: PortalIcon4,
|
||||
value: 'icon-4'
|
||||
},
|
||||
{
|
||||
Component: PortalIcon5,
|
||||
value: 'icon-5'
|
||||
}
|
||||
];
|
||||
|
||||
const LookAndFeel: React.FC<{
|
||||
localSettings: Setting[]
|
||||
updateSetting: (key: string, setting: SettingValue) => void
|
||||
}> = ({localSettings, updateSetting}) => {
|
||||
const [portalButton, portalButtonStyle, portalButtonSignupText] = getSettingValues(localSettings, ['portal_button', 'portal_button_style', 'portal_button_signup_text']);
|
||||
const {fileService} = useContext(ServicesContext);
|
||||
|
||||
const [portalButton, portalButtonStyle, portalButtonIcon, portalButtonSignupText] = getSettingValues(localSettings, ['portal_button', 'portal_button_style', 'portal_button_icon', 'portal_button_signup_text']);
|
||||
|
||||
const currentIcon = portalButtonIcon as string || defaultButtonIcons[0].value;
|
||||
const isDefaultIcon = defaultButtonIcons.map(({value}) => value).includes(currentIcon);
|
||||
|
||||
const [uploadedIcon, setUploadedIcon] = useState(isDefaultIcon ? undefined : currentIcon);
|
||||
|
||||
const handleImageUpload = async (file: File) => {
|
||||
const imageUrl = await fileService!.uploadImage(file);
|
||||
updateSetting('portal_button_icon', imageUrl);
|
||||
setUploadedIcon(imageUrl);
|
||||
};
|
||||
|
||||
const handleImageDelete = () => {
|
||||
updateSetting('portal_button_icon', null);
|
||||
setUploadedIcon(undefined);
|
||||
};
|
||||
|
||||
return <Form marginTop>
|
||||
<Toggle
|
||||
|
@ -29,7 +79,25 @@ const LookAndFeel: React.FC<{
|
|||
title='Portal button style'
|
||||
onSelect={option => updateSetting('portal_button_style', option)}
|
||||
/>
|
||||
{portalButtonStyle?.toString()?.includes('icon') && <div className='red text-sm'>TODO: icon picker</div>}
|
||||
{portalButtonStyle?.toString()?.includes('icon') &&
|
||||
<div className='flex gap-2 border border-green p-4'>
|
||||
{defaultButtonIcons.map(icon => (
|
||||
<button className={clsx('border p-4', currentIcon === icon.value ? 'border-green' : 'border-transparent')} type="button" onClick={() => updateSetting('portal_button_icon', icon.value)}>
|
||||
<icon.Component className="h-6 w-6 text-green" />
|
||||
</button>
|
||||
))}
|
||||
<div className={clsx('w-10 border', currentIcon === uploadedIcon ? 'border-green' : 'border-transparent')}>
|
||||
<ImageUpload
|
||||
id='test'
|
||||
imageClassName='cursor-pointer'
|
||||
imageURL={uploadedIcon}
|
||||
onDelete={handleImageDelete}
|
||||
onImageClick={() => uploadedIcon && updateSetting('portal_button_icon', uploadedIcon)}
|
||||
onUpload={handleImageUpload}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
{portalButtonStyle?.toString()?.includes('text') &&
|
||||
<TextField
|
||||
title='Signup button text'
|
||||
|
|
Loading…
Add table
Reference in a new issue