mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-25 20:03:12 +03:00
AdminX dark mode updates (#18056)
refs. https://github.com/TryGhost/Product/issues/3349 - modals in AdminX were not prepared for dark mode
This commit is contained in:
parent
3755384b66
commit
8064dda566
@ -1 +1 @@
|
|||||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" stroke-width="1.5"><path d="M5.25 12.373h-3" fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round"></path><path d="m5.25 15.373-1.5 1.5" fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round"></path><path d="m5.25 9.373-1.5-1.5" fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round"></path><path d="M18.75 12.373h3" fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round"></path><path d="m18.75 15.373 1.5 1.5" fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round"></path><path d="m18.75 9.373 1.5-1.5" fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round"></path><path d="M8.25 9.373v-4.5A3.762 3.762 0 0 1 12 1.123h0a3.761 3.761 0 0 1 3.75 3.75v5.25a3.763 3.763 0 0 1-2.25 3.435 3.709 3.709 0 0 1-1.5.315" fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round"></path><path d="M15.75 14.623v4.5a3.76 3.76 0 0 1-3.75 3.75h0a3.761 3.761 0 0 1-3.75-3.75v-4.5a3.762 3.762 0 0 1 3.75-3.75" fill="none" stroke="#000000" stroke-linecap="round" stroke-linejoin="round"></path></svg>
|
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" stroke-width="1.5"><path d="M5.25 12.373h-3" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></path><path d="m5.25 15.373-1.5 1.5" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></path><path d="m5.25 9.373-1.5-1.5" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></path><path d="M18.75 12.373h3" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></path><path d="m18.75 15.373 1.5 1.5" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></path><path d="m18.75 9.373 1.5-1.5" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></path><path d="M8.25 9.373v-4.5A3.762 3.762 0 0 1 12 1.123h0a3.761 3.761 0 0 1 3.75 3.75v5.25a3.763 3.763 0 0 1-2.25 3.435 3.709 3.709 0 0 1-1.5.315" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></path><path d="M15.75 14.623v4.5a3.76 3.76 0 0 1-3.75 3.75h0a3.761 3.761 0 0 1-3.75-3.75v-4.5a3.762 3.762 0 0 1 3.75-3.75" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"></path></svg>
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
@ -47,7 +47,7 @@ const Breadcrumbs: React.FC<BreadcrumbsProps> = ({
|
|||||||
return (
|
return (
|
||||||
<div className={containerClassName}>
|
<div className={containerClassName}>
|
||||||
{backIcon &&
|
{backIcon &&
|
||||||
<Button className='mr-6' icon='arrow-left' size='sm' link onClick={onBack} />
|
<Button className='mr-6' icon='arrow-left' iconColorClass='dark:text-white' size='sm' link onClick={onBack} />
|
||||||
}
|
}
|
||||||
{items.map((item) => {
|
{items.map((item) => {
|
||||||
const bcItem = (i === allItems - 1 ?
|
const bcItem = (i === allItems - 1 ?
|
||||||
@ -56,7 +56,7 @@ const Breadcrumbs: React.FC<BreadcrumbsProps> = ({
|
|||||||
<>
|
<>
|
||||||
<button
|
<button
|
||||||
key={`bc-${i}`}
|
key={`bc-${i}`}
|
||||||
className={`${itemClassName} ${item.onClick && '-mx-1 cursor-pointer rounded-sm px-1 py-px hover:bg-grey-100'}`}
|
className={`${itemClassName} ${item.onClick && '-mx-1 cursor-pointer rounded-sm px-1 py-px hover:bg-grey-100 dark:hover:bg-grey-900'}`}
|
||||||
type="button"
|
type="button"
|
||||||
onClick={item.onClick}
|
onClick={item.onClick}
|
||||||
>
|
>
|
||||||
|
@ -78,7 +78,7 @@ const Heading: React.FC<Heading1to5Props | Heading6Props | HeadingLabelProps> =
|
|||||||
|
|
||||||
className = clsx(
|
className = clsx(
|
||||||
styles,
|
styles,
|
||||||
'dark:text-white',
|
!grey && 'dark:text-white',
|
||||||
className
|
className
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ interface IconProps {
|
|||||||
* - all icons must have all it's children color value set `currentColor`
|
* - all icons must have all it's children color value set `currentColor`
|
||||||
* - all strokes must be paths and _NOT_ outlined objects. Stroke width should be set to 1.5px
|
* - all strokes must be paths and _NOT_ outlined objects. Stroke width should be set to 1.5px
|
||||||
*/
|
*/
|
||||||
const Icon: React.FC<IconProps> = ({name, size = 'md', colorClass = 'text-black', className = ''}) => {
|
const Icon: React.FC<IconProps> = ({name, size = 'md', colorClass = '', className = ''}) => {
|
||||||
const {SvgComponent} = useDynamicSVGImport(name);
|
const {SvgComponent} = useDynamicSVGImport(name);
|
||||||
|
|
||||||
let styles = '';
|
let styles = '';
|
||||||
|
@ -44,7 +44,7 @@ const ListItem: React.FC<ListItemProps> = ({
|
|||||||
const listItemClasses = clsx(
|
const listItemClasses = clsx(
|
||||||
'group/list-item flex items-center justify-between',
|
'group/list-item flex items-center justify-between',
|
||||||
bgOnHover && 'hover:bg-gradient-to-r hover:from-white hover:to-grey-50 dark:hover:from-black dark:hover:to-grey-950',
|
bgOnHover && 'hover:bg-gradient-to-r hover:from-white hover:to-grey-50 dark:hover:from-black dark:hover:to-grey-950',
|
||||||
separator ? 'border-b border-grey-100 last-of-type:border-b-transparent hover:border-grey-200 dark:border-grey-800 dark:hover:border-grey-700' : 'border-y border-transparent hover:border-grey-200 first-of-type:hover:border-t-transparent dark:hover:border-grey-700',
|
separator ? 'border-b border-grey-100 last-of-type:border-b-transparent hover:border-grey-200 dark:border-grey-900 dark:hover:border-grey-800' : 'border-y border-transparent hover:border-grey-200 first-of-type:hover:border-t-transparent dark:hover:border-grey-800',
|
||||||
className
|
className
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ const Menu: React.FC<MenuProps> = ({
|
|||||||
<Popover position={position} trigger={trigger} closeOnItemClick>
|
<Popover position={position} trigger={trigger} closeOnItemClick>
|
||||||
<div className="flex min-w-[160px] flex-col justify-stretch py-1" role="none">
|
<div className="flex min-w-[160px] flex-col justify-stretch py-1" role="none">
|
||||||
{items.map(item => (
|
{items.map(item => (
|
||||||
<button key={item.id} className="mx-1 block cursor-pointer rounded-[2.5px] px-4 py-1.5 text-left text-sm hover:bg-grey-100" type="button" onClick={item.onClick}>{item.label}</button>
|
<button key={item.id} className="mx-1 block cursor-pointer rounded-[2.5px] px-4 py-1.5 text-left text-sm hover:bg-grey-100 dark:hover:bg-grey-800" type="button" onClick={item.onClick}>{item.label}</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
@ -65,7 +65,7 @@ const Popover: React.FC<PopoverProps> = ({
|
|||||||
let className = '';
|
let className = '';
|
||||||
|
|
||||||
className = clsx(
|
className = clsx(
|
||||||
'fixed z-50 mt-2 origin-top-right rounded bg-white shadow-md ring-1 ring-[rgba(0,0,0,0.01)] focus:outline-none',
|
'fixed z-50 mt-2 origin-top-right rounded bg-white shadow-md ring-1 ring-[rgba(0,0,0,0.01)] focus:outline-none dark:bg-grey-900 dark:text-white',
|
||||||
className
|
className
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -4,7 +4,10 @@ interface SeparatorProps {
|
|||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Separator: React.FC<SeparatorProps> = ({className = 'border-grey-200 dark:border-grey-800'}) => {
|
const Separator: React.FC<SeparatorProps> = ({className}) => {
|
||||||
|
if (!className) {
|
||||||
|
className = 'border-grey-200 dark:border-grey-600';
|
||||||
|
}
|
||||||
return <hr className={className} />;
|
return <hr className={className} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ const DefaultContainer: React.FC<SortableItemContainerProps> = ({
|
|||||||
<div
|
<div
|
||||||
ref={setRef}
|
ref={setRef}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'group flex w-full items-center gap-3 bg-white py-1',
|
'group flex w-full items-center gap-3 bg-white py-1 dark:bg-black',
|
||||||
separator && 'border-b border-grey-200',
|
separator && 'border-b border-grey-200',
|
||||||
isDragging && 'opacity-75'
|
isDragging && 'opacity-75'
|
||||||
)}
|
)}
|
||||||
|
@ -6,8 +6,8 @@ interface MobileChromeProps {
|
|||||||
|
|
||||||
const MobileChrome: React.FC<MobileChromeProps & React.HTMLAttributes<HTMLDivElement>> = ({children, ...props}) => {
|
const MobileChrome: React.FC<MobileChromeProps & React.HTMLAttributes<HTMLDivElement>> = ({children, ...props}) => {
|
||||||
return (
|
return (
|
||||||
<div className='flex h-[775px] w-[380px] flex-col rounded-3xl bg-white p-2 shadow-xl' {...props}>
|
<div className='flex h-[775px] w-[380px] flex-col rounded-3xl bg-white p-2 shadow-xl dark:bg-grey-900' {...props}>
|
||||||
<div className='w-100 h-100 grow overflow-auto rounded-2xl border border-grey-100'>
|
<div className='w-100 h-100 grow overflow-auto rounded-2xl border border-grey-100 dark:border-grey-950'>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -58,7 +58,7 @@ const Form: React.FC<FormProps> = ({
|
|||||||
if (grouped) {
|
if (grouped) {
|
||||||
classes = clsx(
|
classes = clsx(
|
||||||
classes,
|
classes,
|
||||||
'rounded-sm border border-grey-200 p-4 md:p-7'
|
'rounded-sm border border-grey-200 p-4 dark:border-grey-900 md:p-7'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ const TextArea: React.FC<TextAreaProps> = ({
|
|||||||
|
|
||||||
let styles = clsx(
|
let styles = clsx(
|
||||||
'peer order-2 rounded-sm border px-3 py-2 dark:text-white',
|
'peer order-2 rounded-sm border px-3 py-2 dark:text-white',
|
||||||
clearBg ? 'bg-transparent' : 'bg-grey-75 dark:bg-grey-900',
|
clearBg ? 'bg-transparent' : 'bg-grey-75 dark:bg-grey-950',
|
||||||
error ? 'border-red' : 'border-grey-500 placeholder:text-grey-500 hover:border-grey-700 focus:border-grey-800 dark:border-grey-800 dark:placeholder:text-grey-800 dark:hover:border-grey-700 dark:focus:border-grey-500',
|
error ? 'border-red' : 'border-grey-500 placeholder:text-grey-500 hover:border-grey-700 focus:border-grey-800 dark:border-grey-800 dark:placeholder:text-grey-800 dark:hover:border-grey-700 dark:focus:border-grey-500',
|
||||||
title && 'mt-2',
|
title && 'mt-2',
|
||||||
fontStyle === 'mono' && 'font-mono text-sm',
|
fontStyle === 'mono' && 'font-mono text-sm',
|
||||||
|
@ -67,7 +67,7 @@ const Toggle: React.FC<ToggleProps> = ({
|
|||||||
let toggleBgClass;
|
let toggleBgClass;
|
||||||
switch (toggleBg) {
|
switch (toggleBg) {
|
||||||
case 'stripetest':
|
case 'stripetest':
|
||||||
toggleBgClass = 'checked:bg-[#EC6803]';
|
toggleBgClass = 'checked:bg-[#EC6803] dark:checked:bg-[#EC6803]';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'green':
|
case 'green':
|
||||||
@ -75,7 +75,7 @@ const Toggle: React.FC<ToggleProps> = ({
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
toggleBgClass = 'checked:bg-black';
|
toggleBgClass = 'checked:bg-black dark:checked:bg-green';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ const Toggle: React.FC<ToggleProps> = ({
|
|||||||
<div>
|
<div>
|
||||||
<div className={`group flex items-start gap-2 dark:text-white ${direction === 'rtl' && 'justify-between'} ${separator && 'pb-2'}`}>
|
<div className={`group flex items-start gap-2 dark:text-white ${direction === 'rtl' && 'justify-between'} ${separator && 'pb-2'}`}>
|
||||||
<input checked={checked}
|
<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 dark:checked:bg-green ${sizeStyles} ${direction === 'rtl' && ' order-2'}`}
|
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'}`}
|
||||||
id={id}
|
id={id}
|
||||||
role="switch"
|
role="switch"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
|
@ -247,7 +247,7 @@ const Modal: React.FC<ModalProps> = ({
|
|||||||
<div className={clsx(
|
<div className={clsx(
|
||||||
'pointer-events-none fixed inset-0 z-0',
|
'pointer-events-none fixed inset-0 z-0',
|
||||||
(backDrop && !formSheet) && 'bg-[rgba(98,109,121,0.2)] backdrop-blur-[3px]',
|
(backDrop && !formSheet) && 'bg-[rgba(98,109,121,0.2)] backdrop-blur-[3px]',
|
||||||
formSheet && 'bg-[rgba(98,109,121,0.05)]'
|
formSheet && 'bg-[rgba(98,109,121,0.08)]'
|
||||||
)}></div>
|
)}></div>
|
||||||
<section className={modalClasses} data-testid={testId} style={modalStyles}>
|
<section className={modalClasses} data-testid={testId} style={modalStyles}>
|
||||||
<div className={contentClasses}>
|
<div className={contentClasses}>
|
||||||
|
@ -117,7 +117,8 @@ export const PreviewModalContent: React.FC<PreviewModalProps> = ({
|
|||||||
/>;
|
/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const unSelectedIconColorClass = 'text-grey-500';
|
const selectedIconColorClass = 'text-black dark:text-green';
|
||||||
|
const unSelectedIconColorClass = 'text-grey-500 dark:text-grey-600';
|
||||||
const toolbarRight = deviceSelector && (
|
const toolbarRight = deviceSelector && (
|
||||||
<ButtonGroup
|
<ButtonGroup
|
||||||
buttons={[
|
buttons={[
|
||||||
@ -127,7 +128,7 @@ export const PreviewModalContent: React.FC<PreviewModalProps> = ({
|
|||||||
hideLabel: true,
|
hideLabel: true,
|
||||||
link: true,
|
link: true,
|
||||||
size: 'sm',
|
size: 'sm',
|
||||||
iconColorClass: (view === 'desktop' ? 'text-black' : unSelectedIconColorClass),
|
iconColorClass: (view === 'desktop' ? selectedIconColorClass : unSelectedIconColorClass),
|
||||||
onClick: onSelectDesktopView || (() => {
|
onClick: onSelectDesktopView || (() => {
|
||||||
setView('desktop');
|
setView('desktop');
|
||||||
})
|
})
|
||||||
@ -138,7 +139,7 @@ export const PreviewModalContent: React.FC<PreviewModalProps> = ({
|
|||||||
hideLabel: true,
|
hideLabel: true,
|
||||||
link: true,
|
link: true,
|
||||||
size: 'sm',
|
size: 'sm',
|
||||||
iconColorClass: (view === 'mobile' ? 'text-black' : unSelectedIconColorClass),
|
iconColorClass: (view === 'mobile' ? selectedIconColorClass : unSelectedIconColorClass),
|
||||||
onClick: onSelectMobileView || (() => {
|
onClick: onSelectMobileView || (() => {
|
||||||
setView('mobile');
|
setView('mobile');
|
||||||
})
|
})
|
||||||
@ -149,9 +150,10 @@ export const PreviewModalContent: React.FC<PreviewModalProps> = ({
|
|||||||
|
|
||||||
let previewBgClass = '';
|
let previewBgClass = '';
|
||||||
if (previewBgColor === 'grey') {
|
if (previewBgColor === 'grey') {
|
||||||
previewBgClass = 'bg-grey-50';
|
previewBgClass = 'bg-grey-50 dark:bg-black';
|
||||||
} else if (previewBgColor === 'greygradient') {
|
} else if (previewBgColor === 'greygradient') {
|
||||||
previewBgClass = 'bg-gradient-to-tr from-white to-[#f9f9fa]';
|
previewBgClass = 'bg-gradient-to-tr from-white to-[#f9f9fa]';
|
||||||
|
previewBgClass = 'bg-gradient-to-tr from-grey-950 to-black';
|
||||||
}
|
}
|
||||||
|
|
||||||
const containerClasses = clsx(
|
const containerClasses = clsx(
|
||||||
@ -216,7 +218,7 @@ export const PreviewModalContent: React.FC<PreviewModalProps> = ({
|
|||||||
{preview}
|
{preview}
|
||||||
</div>
|
</div>
|
||||||
{sidebar &&
|
{sidebar &&
|
||||||
<div className='relative flex h-full w-full flex-col border-l border-grey-100 md:w-auto md:basis-[400px]'>
|
<div className='relative flex h-full w-full flex-col border-l border-grey-100 dark:border-grey-900 md:w-auto md:basis-[400px]'>
|
||||||
{sidebarHeader ? sidebarHeader : (
|
{sidebarHeader ? sidebarHeader : (
|
||||||
<div className='flex max-h-[74px] items-center justify-between gap-3 px-7 py-5'>
|
<div className='flex max-h-[74px] items-center justify-between gap-3 px-7 py-5'>
|
||||||
<Heading level={titleHeadingLevel}>{title}</Heading>
|
<Heading level={titleHeadingLevel}>{title}</Heading>
|
||||||
|
@ -4,12 +4,14 @@ import clsx from 'clsx';
|
|||||||
|
|
||||||
interface StripeButtonProps {
|
interface StripeButtonProps {
|
||||||
label?: React.ReactNode;
|
label?: React.ReactNode;
|
||||||
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StripeButton: React.FC<StripeButtonProps | ButtonProps> = ({label, ...props}) => {
|
const StripeButton: React.FC<StripeButtonProps | ButtonProps> = ({label, className, ...props}) => {
|
||||||
const classNames = clsx(
|
const classNames = clsx(
|
||||||
'cursor-pointer rounded-md bg-[#625BF6] font-semibold text-white transition-all hover:opacity-90',
|
'cursor-pointer rounded-md bg-[#625BF6] font-semibold text-white transition-all hover:opacity-90',
|
||||||
label ? 'px-5 py-2 text-sm' : 'px-6 py-[9px]'
|
label ? 'px-5 py-2 text-sm' : 'px-6 py-[9px]',
|
||||||
|
className
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!label) {
|
if (!label) {
|
||||||
|
@ -39,7 +39,7 @@ const HistoryAvatar: React.FC<{action: Action}> = ({action}) => {
|
|||||||
labelColor='white'
|
labelColor='white'
|
||||||
size='md'
|
size='md'
|
||||||
/>
|
/>
|
||||||
<div className='absolute -bottom-1 -right-1 flex items-center justify-center rounded-full border border-grey-100 bg-white p-1 shadow-sm'>
|
<div className='absolute -bottom-1 -right-1 flex items-center justify-center rounded-full border border-grey-100 bg-white p-1 shadow-sm dark:border-grey-900 dark:bg-black'>
|
||||||
<HistoryIcon action={action} />
|
<HistoryIcon action={action} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -96,7 +96,7 @@ const HistoryActionDescription: React.FC<{action: Action}> = ({action}) => {
|
|||||||
|
|
||||||
return <>
|
return <>
|
||||||
{group.slice(0, 1).toUpperCase()}{group.slice(1)}
|
{group.slice(0, 1).toUpperCase()}{group.slice(1)}
|
||||||
{group !== key && <span className='text-xs'> <code className='mb-1 bg-white text-grey-800'>({key})</code></span>}
|
{group !== key && <span className='text-xs'> <code className='mb-1 bg-white text-grey-800 dark:bg-grey-900 dark:text-white'>({key})</code></span>}
|
||||||
</>;
|
</>;
|
||||||
} else if (action.resource?.title || action.resource?.name || action.context.primary_name) {
|
} else if (action.resource?.title || action.resource?.name || action.context.primary_name) {
|
||||||
const linkTarget = getLinkTarget(action);
|
const linkTarget = getLinkTarget(action);
|
||||||
|
@ -19,10 +19,10 @@ const APIKeyField: React.FC<APIKeyFieldProps> = ({label, text = '', hint, onRege
|
|||||||
|
|
||||||
return <>
|
return <>
|
||||||
<div className='p-0 pr-4 text-sm text-grey-600 md:py-1'>{label}</div>
|
<div className='p-0 pr-4 text-sm text-grey-600 md:py-1'>{label}</div>
|
||||||
<div className='group/api-keys relative mb-3 overflow-hidden rounded py-1 text-sm hover:bg-grey-50 md:mb-0 md:p-1'>
|
<div className='group/api-keys relative mb-3 overflow-hidden rounded py-1 text-sm hover:bg-grey-50 dark:hover:bg-grey-900 md:mb-0 md:p-1'>
|
||||||
{text}
|
{text}
|
||||||
{hint}
|
{hint}
|
||||||
<div className='visible absolute right-0 top-[50%] flex translate-y-[-50%] gap-1 bg-white pl-1 text-sm group-hover/api-keys:visible md:invisible'>
|
<div className='visible absolute right-0 top-[50%] flex translate-y-[-50%] gap-1 bg-white pl-1 text-sm group-hover/api-keys:visible dark:bg-black md:invisible'>
|
||||||
{onRegenerate && <Button color='outline' label='Regenerate' size='sm' onClick={onRegenerate} />}
|
{onRegenerate && <Button color='outline' label='Regenerate' size='sm' onClick={onRegenerate} />}
|
||||||
<Button color='outline' label={copied ? 'Copied' : 'Copy'} size='sm' onClick={copyText} />
|
<Button color='outline' label={copied ? 'Copied' : 'Copy'} size='sm' onClick={copyText} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -99,7 +99,7 @@ const PinturaModal = NiceModal.create(() => {
|
|||||||
title='Pintura'
|
title='Pintura'
|
||||||
/>
|
/>
|
||||||
<div className='mt-7'>
|
<div className='mt-7'>
|
||||||
<div className='mb-7 flex flex-col items-stretch justify-between gap-4 rounded-sm bg-grey-75 p-4 md:flex-row md:p-7'>
|
<div className='mb-7 flex flex-col items-stretch justify-between gap-4 rounded-sm bg-grey-75 p-4 dark:bg-grey-950 md:flex-row md:p-7'>
|
||||||
<div className='md:basis-1/2'>
|
<div className='md:basis-1/2'>
|
||||||
<p className='mb-4 font-bold'>Add advanced image editing to Ghost, with Pintura</p>
|
<p className='mb-4 font-bold'>Add advanced image editing to Ghost, with Pintura</p>
|
||||||
<p className='mb-4 text-sm'>Pintura is a powerful JavaScript image editor that allows you to crop, rotate, annotate and modify images directly inside Ghost.</p>
|
<p className='mb-4 text-sm'>Pintura is a powerful JavaScript image editor that allows you to crop, rotate, annotate and modify images directly inside Ghost.</p>
|
||||||
|
@ -102,7 +102,7 @@ const ZapierModal = NiceModal.create(() => {
|
|||||||
title={
|
title={
|
||||||
<div className='flex flex-col gap-4 md:flex-row md:items-center'>
|
<div className='flex flex-col gap-4 md:flex-row md:items-center'>
|
||||||
<div className='flex shrink-0 flex-nowrap items-center gap-2'>
|
<div className='flex shrink-0 flex-nowrap items-center gap-2'>
|
||||||
<img className='h-8 w-8 object-contain' role='presentation' src={`${adminRoot}${template.ghostImage}`} />
|
<img className='h-8 w-8 object-contain dark:invert' role='presentation' src={`${adminRoot}${template.ghostImage}`} />
|
||||||
<ArrowRightIcon className='h-3 w-3' />
|
<ArrowRightIcon className='h-3 w-3' />
|
||||||
<img className='h-8 w-8 object-contain' role='presentation' src={`${adminRoot}${template.appImage}`} />
|
<img className='h-8 w-8 object-contain' role='presentation' src={`${adminRoot}${template.appImage}`} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -30,7 +30,7 @@ const ImportModalContent = () => {
|
|||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="cursor-pointer bg-grey-100 p-10 text-center">
|
<div className="cursor-pointer bg-grey-75 p-10 text-center dark:bg-grey-950">
|
||||||
{uploading ? 'Uploading ...' : 'Select a JSON or zip file'}
|
{uploading ? 'Uploading ...' : 'Select a JSON or zip file'}
|
||||||
</div>
|
</div>
|
||||||
</FileUpload>;
|
</FileUpload>;
|
||||||
|
@ -40,8 +40,8 @@ const LockSite: React.FC<{ keywords: string[] }> = ({keywords}) => {
|
|||||||
<span>Your site is password protected</span>
|
<span>Your site is password protected</span>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className='flex items-center gap-1 text-grey-900'>
|
<div className='flex items-center gap-1 text-grey-900 dark:text-grey-400'>
|
||||||
<Icon colorClass='text-black' name='lock-unlocked' size='sm' />
|
<Icon colorClass='text-black dark:text-white' name='lock-unlocked' size='sm' />
|
||||||
<span>Your site is not password protected</span>
|
<span>Your site is not password protected</span>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -57,8 +57,8 @@ const RoleSelector: React.FC<UserDetailProps> = ({user, setUserData}) => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Heading level={6}>Role</Heading>
|
<Heading level={6}>Role</Heading>
|
||||||
<div className='flex h-[295px] flex-col items-center justify-center gap-3 bg-grey-75 px-10 py-20 text-center text-sm text-grey-800'>
|
<div className='flex h-[295px] flex-col items-center justify-center gap-3 bg-grey-75 px-10 py-20 text-center text-sm text-grey-800 dark:bg-grey-950 dark:text-white'>
|
||||||
<Icon colorClass='text-grey-800' name='crown' size='lg' />
|
<Icon colorClass='text-grey-800 dark:text-white' name='crown' size='lg' />
|
||||||
This user is the owner of the site. To change their role, you need to transfer the ownership first.
|
This user is the owner of the site. To change their role, you need to transfer the ownership first.
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
@ -86,7 +86,7 @@ const LookAndFeel: React.FC<{
|
|||||||
|
|
||||||
{defaultButtonIcons.map(icon => (
|
{defaultButtonIcons.map(icon => (
|
||||||
<button className={clsx('border p-3', currentIcon === icon.value ? 'border-green' : 'border-transparent')} type="button" onClick={() => updateSetting('portal_button_icon', icon.value)}>
|
<button className={clsx('border p-3', currentIcon === icon.value ? 'border-green' : 'border-transparent')} type="button" onClick={() => updateSetting('portal_button_icon', icon.value)}>
|
||||||
<icon.Component className={`h-5 w-5 ${currentIcon === icon.value ? 'text-green' : 'text-black opacity-70 transition-all hover:opacity-100'}`} />
|
<icon.Component className={`h-5 w-5 ${currentIcon === icon.value ? 'text-green' : 'text-black opacity-70 transition-all hover:opacity-100 dark:text-white'}`} />
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
<div className={clsx('relative w-[46px] border', currentIcon === uploadedIcon ? 'border-green' : 'border-transparent')}>
|
<div className={clsx('relative w-[46px] border', currentIcon === uploadedIcon ? 'border-green' : 'border-transparent')}>
|
||||||
@ -103,7 +103,7 @@ const LookAndFeel: React.FC<{
|
|||||||
onImageClick={() => uploadedIcon && updateSetting('portal_button_icon', uploadedIcon)}
|
onImageClick={() => uploadedIcon && updateSetting('portal_button_icon', uploadedIcon)}
|
||||||
onUpload={handleImageUpload}
|
onUpload={handleImageUpload}
|
||||||
>
|
>
|
||||||
<Icon name='upload' size='md' />
|
<Icon className='dark:text-white' name='upload' size='md' />
|
||||||
</ImageUpload>
|
</ImageUpload>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -134,12 +134,12 @@ const Connect: React.FC = () => {
|
|||||||
onChange={e => setTestMode(e.target.checked)}
|
onChange={e => setTestMode(e.target.checked)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Heading level={6} grey>Step 1 — <span className='text-black'>Generate secure key</span></Heading>
|
<Heading level={6} grey>Step 1 — <span className='text-black dark:text-white'>Generate secure key</span></Heading>
|
||||||
<div className='mb-4 mt-2'>
|
<div className='mb-4 mt-2'>
|
||||||
Click on the <strong>“Connect with Stripe”</strong> button to generate a secure key that connects your Ghost site with Stripe.
|
Click on the <strong>“Connect with Stripe”</strong> button to generate a secure key that connects your Ghost site with Stripe.
|
||||||
</div>
|
</div>
|
||||||
<StripeButton href={stripeConnectUrl} tag='a' target='_blank' />
|
<StripeButton href={stripeConnectUrl} tag='a' target='_blank' />
|
||||||
<Heading className='mb-2 mt-8' level={6} grey>Step 2 — <span className='text-black'>Paste secure key</span></Heading>
|
<Heading className='mb-2 mt-8' level={6} grey>Step 2 — <span className='text-black dark:text-white'>Paste secure key</span></Heading>
|
||||||
<TextArea clearBg={false} error={Boolean(error)} hint={error || undefined} placeholder='Paste your secure key here' onChange={onTokenChange}></TextArea>
|
<TextArea clearBg={false} error={Boolean(error)} hint={error || undefined} placeholder='Paste your secure key here' onChange={onTokenChange}></TextArea>
|
||||||
{submitEnabled && <Button className='mt-5' color='green' label='Save Stripe settings' onClick={onSubmit} />}
|
{submitEnabled && <Button className='mt-5' color='green' label='Save Stripe settings' onClick={onSubmit} />}
|
||||||
</div>
|
</div>
|
||||||
@ -185,24 +185,24 @@ const Connected: React.FC<{onClose?: () => void}> = ({onClose}) => {
|
|||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
<div className='flex items-center justify-between'>
|
<div className='flex items-center justify-between'>
|
||||||
<Button disabled={isFetchingMembers} icon='link-broken' label='Disconnect' link onClick={openDisconnectStripeModal} />
|
<Button className='dark:text-white' disabled={isFetchingMembers} icon='link-broken' iconColorClass='dark:text-white' label='Disconnect' link onClick={openDisconnectStripeModal} />
|
||||||
<Button icon='close' label='Close' size='sm' hideLabel link onClick={onClose} />
|
<Button icon='close' iconColorClass='dark:text-white' label='Close' size='sm' hideLabel link onClick={onClose} />
|
||||||
</div>
|
</div>
|
||||||
<div className='my-20 flex flex-col items-center'>
|
<div className='my-20 flex flex-col items-center'>
|
||||||
<div className='relative h-20 w-[200px]'>
|
<div className='relative h-20 w-[200px]'>
|
||||||
<img alt='Ghost Logo' className='absolute left-10 h-16 w-16' src={GhostLogo} />
|
<img alt='Ghost Logo' className='absolute left-10 h-16 w-16' src={GhostLogo} />
|
||||||
<img alt='Stripe Logo' className='absolute right-10 h-16 w-16 rounded-2xl shadow-[-1.5px_0_0_1.5px_#fff]' src={StripeLogo} />
|
<img alt='Stripe Logo' className='absolute right-10 h-16 w-16 rounded-2xl shadow-[-1.5px_0_0_1.5px_#fff] dark:shadow-[-1.5px_0_0_1.5px_black]' src={StripeLogo} />
|
||||||
</div>
|
</div>
|
||||||
<Heading className='text-center' level={3}>You are connected with Stripe!{stripeConnectLivemode ? null : ' (Test mode)'}</Heading>
|
<Heading className='text-center' level={3}>You are connected with Stripe!{stripeConnectLivemode ? null : ' (Test mode)'}</Heading>
|
||||||
<div className='mt-1'>Connected to <strong>Dummy</strong></div>
|
<div className='mt-1'>Connected to <strong>Dummy</strong></div>
|
||||||
</div>
|
</div>
|
||||||
<div className='flex flex-col items-center'>
|
<div className='flex flex-col items-center'>
|
||||||
<Heading level={6}>Read next</Heading>
|
<Heading level={6}>Read next</Heading>
|
||||||
<a className='w-100 mt-5 flex flex-col items-stretch justify-between border border-grey-200 transition-all hover:border-grey-400 md:flex-row' href="https://ghost.org/resources/managing-your-stripe-account/?ref=admin" rel="noopener noreferrer" target="_blank">
|
<a className='w-100 mt-5 flex flex-col items-stretch justify-between rounded-sm border border-grey-200 transition-all hover:border-grey-400 dark:border-grey-900 md:flex-row' href="https://ghost.org/resources/managing-your-stripe-account/?ref=admin" rel="noopener noreferrer" target="_blank">
|
||||||
<div className='order-2 p-4 md:order-1'>
|
<div className='order-2 p-4 md:order-1'>
|
||||||
<div className='font-bold'>How to setup and manage your Stripe account</div>
|
<div className='font-bold'>How to setup and manage your Stripe account</div>
|
||||||
<div className='mt-1 text-sm text-grey-800'>Learn how to configure your Stripe account to work with Ghost, from custom branding to payment receipt emails.</div>
|
<div className='mt-1 text-sm text-grey-800 dark:text-grey-500'>Learn how to configure your Stripe account to work with Ghost, from custom branding to payment receipt emails.</div>
|
||||||
<div className='mt-3 flex items-center gap-1 text-sm text-grey-800'>
|
<div className='mt-3 flex items-center gap-1 text-sm text-grey-800 dark:text-grey-500'>
|
||||||
<img alt='Ghost Logo' className='h-4 w-4' src={GhostLogoPink} />
|
<img alt='Ghost Logo' className='h-4 w-4' src={GhostLogoPink} />
|
||||||
<strong>Ghost Resources</strong>
|
<strong>Ghost Resources</strong>
|
||||||
<span>·</span>
|
<span>·</span>
|
||||||
|
@ -230,7 +230,7 @@ const TierDetailModalContent: React.FC<{tier?: Tier}> = ({tier}) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="relative mt-0.5 flex items-center gap-3">
|
<div className="relative mt-0.5 flex items-center gap-3">
|
||||||
<Icon name='check' size='sm' />
|
<Icon className='dark:text-white' name='check' size='sm' />
|
||||||
<TextField
|
<TextField
|
||||||
className='grow'
|
className='grow'
|
||||||
containerClassName='w-100'
|
containerClassName='w-100'
|
||||||
|
@ -82,15 +82,15 @@ const TierDetailPreview: React.FC<TierDetailPreviewProps> = ({tier, isFreeTier})
|
|||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mt-1">
|
<div>
|
||||||
<div className="flex items-baseline justify-between">
|
<div className="flex items-baseline justify-between">
|
||||||
<Heading className="pb-2" level={6} grey>{isFreeTier ? 'Free membership preview' : 'Tier preview'}</Heading>
|
<Heading className="pb-2" level={6} grey>{isFreeTier ? 'Free membership preview' : 'Tier preview'}</Heading>
|
||||||
{!isFreeTier && <div className="flex gap-1">
|
{!isFreeTier && <div className="flex gap-1">
|
||||||
<Button className={`${showingYearly === true ? 'text-grey-500' : 'text-grey-900'}`} label="Monthly" link onClick={() => setShowingYearly(false)} />
|
<Button className={`${showingYearly === true ? 'text-grey-500' : 'text-grey-900 dark:text-white'}`} label="Monthly" link unstyled onClick={() => setShowingYearly(false)} />
|
||||||
<Button className={`ml-2 ${showingYearly === true ? 'text-grey-900' : 'text-grey-500'}`} label="Yearly" link onClick={() => setShowingYearly(true)} />
|
<Button className={`ml-2 ${showingYearly === true ? 'text-grey-900 dark:text-white' : 'text-grey-500'}`} label="Yearly" link unstyled onClick={() => setShowingYearly(true)} />
|
||||||
</div>}
|
</div>}
|
||||||
</div>
|
</div>
|
||||||
<div className='border border-grey-200'>
|
<div className='rounded-sm border border-grey-200 bg-white dark:border-transparent'>
|
||||||
<div className="flex-column relative flex min-h-[200px] w-full max-w-[420px] scale-90 items-start justify-stretch rounded bg-white p-4">
|
<div className="flex-column relative flex min-h-[200px] w-full max-w-[420px] scale-90 items-start justify-stretch rounded bg-white p-4">
|
||||||
<div className="min-h-[56px] w-full">
|
<div className="min-h-[56px] w-full">
|
||||||
<h4 className={`-mt-1 mb-0 w-full break-words text-lg font-semibold leading-tight text-pink ${!name && 'opacity-30'}`}>{name || 'Bronze'}</h4>
|
<h4 className={`-mt-1 mb-0 w-full break-words text-lg font-semibold leading-tight text-pink ${!name && 'opacity-30'}`}>{name || 'Bronze'}</h4>
|
||||||
|
@ -75,7 +75,7 @@ const Sidebar: React.FC<{
|
|||||||
<div className='font-semibold'>Change theme</div>
|
<div className='font-semibold'>Change theme</div>
|
||||||
<div className='font-sm text-grey-700'>Current theme: {activeTheme?.name}</div>
|
<div className='font-sm text-grey-700'>Current theme: {activeTheme?.name}</div>
|
||||||
</div>
|
</div>
|
||||||
<Icon className='mr-2 transition-all group-hover:translate-x-2' name='chevron-right' size='sm' />
|
<Icon className='mr-2 transition-all group-hover:translate-x-2 dark:text-white' name='chevron-right' size='sm' />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</StickyFooter>
|
</StickyFooter>
|
||||||
|
@ -182,7 +182,7 @@ const ThemeToolbar: React.FC<ThemeToolbarProps> = ({
|
|||||||
</div>;
|
</div>;
|
||||||
|
|
||||||
return (<>
|
return (<>
|
||||||
<PageHeader containerClassName='bg-white' left={left} right={right} />
|
<PageHeader containerClassName='bg-white dark:bg-black' left={left} right={right} />
|
||||||
<div className='px-[8vmin] md:hidden'>
|
<div className='px-[8vmin] md:hidden'>
|
||||||
<TabView
|
<TabView
|
||||||
border={false}
|
border={false}
|
||||||
|
@ -14,7 +14,7 @@ const NavigationEditForm: React.FC<{
|
|||||||
itemSeparator={false}
|
itemSeparator={false}
|
||||||
renderItem={item => (
|
renderItem={item => (
|
||||||
<NavigationItemEditor
|
<NavigationItemEditor
|
||||||
action={<Button className='self-center' icon="trash" size='sm' onClick={() => navigation.removeItem(item.id)} />}
|
action={<Button className='self-center' icon="trash" iconColorClass='dark:text-white' size='sm' onClick={() => navigation.removeItem(item.id)} />}
|
||||||
baseUrl={baseUrl}
|
baseUrl={baseUrl}
|
||||||
clearError={key => navigation.clearError(item.id, key)}
|
clearError={key => navigation.clearError(item.id, key)}
|
||||||
item={item}
|
item={item}
|
||||||
|
@ -78,7 +78,7 @@ const ThemePreview: React.FC<{
|
|||||||
buttons={[
|
buttons={[
|
||||||
{
|
{
|
||||||
icon: 'laptop',
|
icon: 'laptop',
|
||||||
iconColorClass: (previewMode === 'desktop' ? 'text-black' : 'text-grey-500'),
|
iconColorClass: (previewMode === 'desktop' ? 'text-black dark:text-green' : 'text-grey-500 dark:text-grey-600'),
|
||||||
link: true,
|
link: true,
|
||||||
size: 'sm',
|
size: 'sm',
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
@ -87,7 +87,7 @@ const ThemePreview: React.FC<{
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'mobile',
|
icon: 'mobile',
|
||||||
iconColorClass: (previewMode === 'mobile' ? 'text-black' : 'text-grey-500'),
|
iconColorClass: (previewMode === 'mobile' ? 'text-black dark:text-green' : 'text-grey-500 dark:text-grey-600'),
|
||||||
link: true,
|
link: true,
|
||||||
size: 'sm',
|
size: 'sm',
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
@ -106,8 +106,8 @@ const ThemePreview: React.FC<{
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='absolute inset-0 z-[100]'>
|
<div className='absolute inset-0 z-[100]'>
|
||||||
<PageHeader containerClassName='bg-grey-50 z-[100]' left={left} right={right} sticky={false} />
|
<PageHeader containerClassName='bg-grey-50 dark:bg-black z-[100]' left={left} right={right} sticky={false} />
|
||||||
<div className='flex h-[calc(100%-74px)] grow flex-col items-center justify-center bg-grey-50'>
|
<div className='flex h-[calc(100%-74px)] grow flex-col items-center justify-center bg-grey-50 dark:bg-black'>
|
||||||
{previewMode === 'desktop' ?
|
{previewMode === 'desktop' ?
|
||||||
<DesktopChrome>
|
<DesktopChrome>
|
||||||
<iframe className='h-full w-full'
|
<iframe className='h-full w-full'
|
||||||
|
Loading…
Reference in New Issue
Block a user