mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-13 22:41:32 -05:00
Improved recommendations settings design (#18330)
refs https://github.com/TryGhost/Product/issues/3948, https://github.com/TryGhost/Product/issues/3941 - Added `counter` prop to `TabView` and updated Recommendations.tsx to use it - Improved dark mode design for recommendation settings
This commit is contained in:
parent
907796d857
commit
fac61e4d30
7 changed files with 32 additions and 24 deletions
|
@ -4,6 +4,7 @@ import clsx from 'clsx';
|
||||||
export type Tab<ID = string> = {
|
export type Tab<ID = string> = {
|
||||||
id: ID;
|
id: ID;
|
||||||
title: string;
|
title: string;
|
||||||
|
counter?: number | null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optional, so you can just use the tabs to other views
|
* Optional, so you can just use the tabs to other views
|
||||||
|
@ -51,21 +52,26 @@ function TabView<ID extends string = string>({
|
||||||
<section>
|
<section>
|
||||||
<div className={containerClasses} role='tablist'>
|
<div className={containerClasses} role='tablist'>
|
||||||
{tabs.map(tab => (
|
{tabs.map(tab => (
|
||||||
<button
|
<div>
|
||||||
key={tab.id}
|
<button
|
||||||
aria-selected={selectedTab === tab.id}
|
key={tab.id}
|
||||||
className={clsx(
|
aria-selected={selectedTab === tab.id}
|
||||||
'-m-b-px cursor-pointer appearance-none whitespace-nowrap py-1 text-sm transition-all after:invisible after:block after:h-px after:overflow-hidden after:font-bold after:text-transparent after:content-[attr(title)] dark:text-white',
|
className={clsx(
|
||||||
border && 'border-b-[3px]',
|
'-m-b-px cursor-pointer appearance-none whitespace-nowrap py-1 text-sm transition-all after:invisible after:block after:h-px after:overflow-hidden after:font-bold after:text-transparent after:content-[attr(title)] dark:text-white',
|
||||||
selectedTab === tab.id && border ? 'border-black dark:border-white' : 'border-transparent hover:border-grey-500',
|
border && 'border-b-[3px]',
|
||||||
selectedTab === tab.id && 'font-bold'
|
selectedTab === tab.id && border ? 'border-black dark:border-white' : 'border-transparent hover:border-grey-500',
|
||||||
)}
|
selectedTab === tab.id && 'font-bold'
|
||||||
id={tab.id}
|
)}
|
||||||
role='tab'
|
id={tab.id}
|
||||||
title={tab.title}
|
role='tab'
|
||||||
type="button"
|
title={tab.title}
|
||||||
onClick={handleTabChange}
|
type="button"
|
||||||
>{tab.title}</button>
|
onClick={handleTabChange}
|
||||||
|
>
|
||||||
|
{tab.title}
|
||||||
|
{((typeof tab.counter === 'number' && tab.counter !== null)) && <span className='ml-1.5 rounded-full bg-grey-200 px-1.5 py-[2px] text-xs font-normal text-grey-800 dark:bg-grey-900 dark:text-grey-300'>{tab.counter}</span>}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
{tabs.map((tab) => {
|
{tabs.map((tab) => {
|
||||||
|
|
|
@ -28,7 +28,7 @@ const TableRow: React.FC<TableRowProps> = ({id, action, hideActions, className,
|
||||||
'group/table-row',
|
'group/table-row',
|
||||||
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',
|
||||||
onClick && 'cursor-pointer',
|
onClick && 'cursor-pointer',
|
||||||
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-none first-of-type:hover:border-t-transparent',
|
separator ? 'border-b border-grey-100 last-of-type:border-b-transparent hover:border-grey-200 dark:border-grey-950 dark:hover:border-grey-900' : 'border-y border-none first-of-type:hover:border-t-transparent',
|
||||||
className
|
className
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -68,12 +68,14 @@ const Recommendations: React.FC<{ keywords: string[] }> = ({keywords}) => {
|
||||||
const tabs = [
|
const tabs = [
|
||||||
{
|
{
|
||||||
id: 'your-recommendations',
|
id: 'your-recommendations',
|
||||||
title: `Your recommendations ${recommendationsMeta?.pagination?.total ? `(${recommendationsMeta.pagination.total})` : ''}`,
|
title: `Your recommendations`,
|
||||||
|
counter: recommendationsMeta?.pagination?.total,
|
||||||
contents: <RecommendationList isLoading={areRecommendationsLoading} recommendations={recommendations ?? []} showMore={showMoreRecommendations}/>
|
contents: <RecommendationList isLoading={areRecommendationsLoading} recommendations={recommendations ?? []} showMore={showMoreRecommendations}/>
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'recommending-you',
|
id: 'recommending-you',
|
||||||
title: `Recommending you ${mentionsPagination?.total ? `(${mentionsPagination.total})` : ''}`,
|
title: `Recommending you`,
|
||||||
|
counter: mentionsPagination?.total,
|
||||||
contents: <IncomingRecommendationList isLoading={areMentionsLoading || areSourcesLoading} mentions={mentions ?? []} pagination={mentionsPagination} stats={mentionsStats ?? []}/>
|
contents: <IncomingRecommendationList isLoading={areMentionsLoading || areSourcesLoading} mentions={mentions ?? []} pagination={mentionsPagination} stats={mentionsStats ?? []}/>
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
|
@ -67,7 +67,7 @@ const IncomingRecommendationItem: React.FC<{mention: Mention, stats: ReferrerHis
|
||||||
</TableCell>
|
</TableCell>
|
||||||
{hasPaidColumn &&
|
{hasPaidColumn &&
|
||||||
<TableCell className='hidden align-middle md:!visible md:!table-cell' onClick={showDetails}>
|
<TableCell className='hidden align-middle md:!visible md:!table-cell' onClick={showDetails}>
|
||||||
{paidConversions === 0 && <span className="text-grey-500">-</span>}
|
{paidConversions === 0 && <span className="dark:text-grey-900">-</span>}
|
||||||
{paidConversions > 0 && (<div className='-mt-px flex grow items-end gap-1'><span>{paidConversions}</span><span className='whitespace-nowrap text-xs text-grey-700'>{paidConversionsLabel}</span></div>)}
|
{paidConversions > 0 && (<div className='-mt-px flex grow items-end gap-1'><span>{paidConversions}</span><span className='whitespace-nowrap text-xs text-grey-700'>{paidConversionsLabel}</span></div>)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ const RecommendationIcon: React.FC<Props> = ({title, favicon, featured_image, is
|
||||||
const hint = isGhostSite ? 'This is a Ghost site that supports one-click subscribe' : '';
|
const hint = isGhostSite ? 'This is a Ghost site that supports one-click subscribe' : '';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative h-6 w-6" title={hint}>
|
<div className="relative h-6 w-6 shrink-0 rounded-sm dark:bg-white" title={hint}>
|
||||||
<img alt={title} className="h-6 w-6 rounded-sm" src={icon} onError={clearIcon} />
|
<img alt={title} className="h-6 w-6 rounded-sm" src={icon} onError={clearIcon} />
|
||||||
{isGhostSite && <img alt='Ghost Logo' className='absolute bottom-[-3px] right-[-3px] h-[14px] w-[14px]' src={GhostLogo} />}
|
{isGhostSite && <img alt='Ghost Logo' className='absolute bottom-[-3px] right-[-3px] h-[14px] w-[14px]' src={GhostLogo} />}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -52,7 +52,7 @@ const RecommendationItem: React.FC<{recommendation: Recommendation}> = ({recomme
|
||||||
</div>
|
</div>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className='hidden w-8 align-middle md:!visible md:!table-cell' onClick={showDetails}>
|
<TableCell className='hidden w-8 align-middle md:!visible md:!table-cell' onClick={showDetails}>
|
||||||
{(count === 0) ? (<span className="text-grey-500">-</span>) : (<div className='-mt-px flex grow items-end gap-1'>
|
{(count === 0) ? (<span className="text-grey-500 dark:text-grey-900">-</span>) : (<div className='-mt-px flex grow items-end gap-1'>
|
||||||
<span>{count}</span>
|
<span>{count}</span>
|
||||||
<span className='-mb-px whitespace-nowrap text-sm lowercase text-grey-700'>{isGhostSite ? newMembers : clicks}</span>
|
<span className='-mb-px whitespace-nowrap text-sm lowercase text-grey-700'>{isGhostSite ? newMembers : clicks}</span>
|
||||||
</div>)}
|
</div>)}
|
||||||
|
|
|
@ -25,11 +25,11 @@ const RecommendationReasonForm: React.FC<Props<EditOrAddRecommendation | Recomme
|
||||||
<Heading className='mb-2 block text-2xs font-semibold uppercase tracking-wider' grey={true} level={6}>Preview</Heading>
|
<Heading className='mb-2 block text-2xs font-semibold uppercase tracking-wider' grey={true} level={6}>Preview</Heading>
|
||||||
<a className='flex items-center justify-between rounded-sm border border-grey-300 bg-white p-3' href={formState.url} rel="noopener noreferrer" target="_blank">
|
<a className='flex items-center justify-between rounded-sm border border-grey-300 bg-white p-3' href={formState.url} rel="noopener noreferrer" target="_blank">
|
||||||
<div className='flex flex-col gap-[2px]'>
|
<div className='flex flex-col gap-[2px]'>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-start gap-2">
|
||||||
<RecommendationIcon {...formState} />
|
<RecommendationIcon {...formState} />
|
||||||
<span className='line-clamp-1 text-[1.6rem] font-semibold text-grey-900'>{formState.title}</span>
|
<span className='text-[1.6rem] font-semibold text-grey-900'>{formState.title}</span>
|
||||||
</div>
|
</div>
|
||||||
{formState.reason && <span className='pl-[29px] text-[1.35rem] leading-snug text-grey-700'>{formState.reason}</span>}
|
{formState.reason && <span className='pl-[31px] text-[1.35rem] leading-snug text-grey-700'>{formState.reason}</span>}
|
||||||
</div>
|
</div>
|
||||||
{formState.one_click_subscribe && <span className='flex whitespace-nowrap pl-6 text-md font-semibold text-green'>Subscribe</span>}
|
{formState.one_click_subscribe && <span className='flex whitespace-nowrap pl-6 text-md font-semibold text-green'>Subscribe</span>}
|
||||||
</a>
|
</a>
|
||||||
|
|
Loading…
Add table
Reference in a new issue