0
Fork 0
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:
Djordje Vlaisavljevic 2023-09-25 13:14:35 +01:00 committed by GitHub
parent 907796d857
commit fac61e4d30
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 32 additions and 24 deletions

View file

@ -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) => {

View file

@ -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
); );

View file

@ -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 ?? []}/>
} }
]; ];

View file

@ -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>
} }

View file

@ -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>

View file

@ -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>)}

View file

@ -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>