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

Made the tabs sticky in design and newsletter settings (#21477)

ref DES-927, DES-928
This commit is contained in:
Sodbileg Gansukh 2024-10-31 13:30:25 +08:00 committed by GitHub
parent 87e24f6403
commit e01b952ed2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 23 additions and 18 deletions

View file

@ -50,7 +50,7 @@ export const TabButton: React.FC<TabButtonProps> = ({
> >
{icon && <Icon className='mb-0.5 mr-1.5 inline' name={icon} size='sm' />} {icon && <Icon className='mb-0.5 mr-1.5 inline' name={icon} size='sm' />}
{title} {title}
{(typeof counter === 'number') && {(typeof counter === 'number') &&
<span className='ml-1.5 rounded-full bg-grey-200 px-1.5 py-[2px] text-xs font-medium text-grey-800 dark:bg-grey-900 dark:text-grey-300'> <span className='ml-1.5 rounded-full bg-grey-200 px-1.5 py-[2px] text-xs font-medium text-grey-800 dark:bg-grey-900 dark:text-grey-300'>
{new Intl.NumberFormat().format(counter)} {new Intl.NumberFormat().format(counter)}
</span> </span>
@ -66,7 +66,8 @@ export interface TabListProps<ID = string> {
border: boolean; border: boolean;
buttonBorder?: boolean; buttonBorder?: boolean;
selectedTab?: ID, selectedTab?: ID,
topRightContent?: React.ReactNode topRightContent?: React.ReactNode,
stickyHeader?: boolean
} }
export const TabList: React.FC<TabListProps> = ({ export const TabList: React.FC<TabListProps> = ({
@ -75,7 +76,8 @@ export const TabList: React.FC<TabListProps> = ({
handleTabChange, handleTabChange,
border, border,
buttonBorder, buttonBorder,
topRightContent topRightContent,
stickyHeader
}) => { }) => {
const containerClasses = clsx( const containerClasses = clsx(
'no-scrollbar mb-px flex w-full overflow-x-auto', 'no-scrollbar mb-px flex w-full overflow-x-auto',
@ -85,7 +87,7 @@ export const TabList: React.FC<TabListProps> = ({
border && 'border-b border-grey-300 dark:border-grey-900' border && 'border-b border-grey-300 dark:border-grey-900'
); );
return ( return (
<TabsPrimitive.List> <TabsPrimitive.List className={`${stickyHeader ? 'sticky top-0 z-50 bg-white dark:bg-black' : ''}`}>
<div className={containerClasses} role='tablist'> <div className={containerClasses} role='tablist'>
{tabs.map(tab => ( {tabs.map(tab => (
<div> <div>
@ -117,6 +119,7 @@ export interface TabViewProps<ID = string> {
width?: TabWidth; width?: TabWidth;
containerClassName?: string; containerClassName?: string;
topRightContent?: React.ReactNode; topRightContent?: React.ReactNode;
stickyHeader?: boolean;
testId?: string; testId?: string;
} }
@ -129,7 +132,8 @@ function TabView<ID extends string = string>({
buttonBorder = border, buttonBorder = border,
width = 'normal', width = 'normal',
containerClassName, containerClassName,
topRightContent topRightContent,
stickyHeader
}: TabViewProps<ID>) { }: TabViewProps<ID>) {
if (tabs.length !== 0 && selectedTab === undefined) { if (tabs.length !== 0 && selectedTab === undefined) {
selectedTab = tabs[0].id; selectedTab = tabs[0].id;
@ -151,6 +155,7 @@ function TabView<ID extends string = string>({
buttonBorder={buttonBorder} buttonBorder={buttonBorder}
handleTabChange={handleTabChange} handleTabChange={handleTabChange}
selectedTab={selectedTab} selectedTab={selectedTab}
stickyHeader={stickyHeader}
tabs={tabs} tabs={tabs}
topRightContent={topRightContent} topRightContent={topRightContent}
width={width} width={width}

View file

@ -514,8 +514,8 @@ const Sidebar: React.FC<{
return ( return (
<div className='flex flex-col'> <div className='flex flex-col'>
<div className='px-7 pb-7 pt-5'> <div className='px-7 pb-7 pt-0'>
<TabView selectedTab={selectedTab} tabs={tabs} onTabChange={handleTabChange} /> <TabView selectedTab={selectedTab} stickyHeader={true} tabs={tabs} onTabChange={handleTabChange} />
</div> </div>
</div> </div>
); );

View file

@ -31,7 +31,7 @@ const Sidebar: React.FC<{
const tabs: Tab[] = [ const tabs: Tab[] = [
{ {
id: 'global', id: 'global',
title: 'Global', title: 'Brand',
contents: <GlobalSettings updateSetting={updateGlobalSetting} values={globalSettings} /> contents: <GlobalSettings updateSetting={updateGlobalSetting} values={globalSettings} />
} }
]; ];
@ -39,7 +39,7 @@ const Sidebar: React.FC<{
if (themeSettingSections.length > 0) { if (themeSettingSections.length > 0) {
tabs.push({ tabs.push({
id: 'theme-settings', id: 'theme-settings',
title: 'Theme settings', title: 'Theme',
contents: <ThemeSettings sections={themeSettingSections} updateSetting={updateThemeSetting} /> contents: <ThemeSettings sections={themeSettingSections} updateSetting={updateThemeSetting} />
}); });
} }
@ -51,9 +51,9 @@ const Sidebar: React.FC<{
return ( return (
<div className='flex h-full flex-col justify-between'> <div className='flex h-full flex-col justify-between'>
<div className='grow p-7 pt-2' data-testid="design-setting-tabs"> <div className='grow p-7 pt-0' data-testid="design-setting-tabs">
{tabs.length > 1 ? {tabs.length > 1 ?
<TabView selectedTab={selectedTab} tabs={tabs} onTabChange={handleTabChange} /> <TabView selectedTab={selectedTab} stickyHeader={true} tabs={tabs} onTabChange={handleTabChange} />
: :
<GlobalSettings updateSetting={updateGlobalSetting} values={globalSettings} /> <GlobalSettings updateSetting={updateGlobalSetting} values={globalSettings} />
} }

View file

@ -89,7 +89,7 @@ test.describe('Design settings', async () => {
await section.getByRole('button', {name: 'Customize'}).click(); await section.getByRole('button', {name: 'Customize'}).click();
await modal.getByTestId('design-setting-tabs').getByRole('tab', {name: 'Theme settings'}).click(); await modal.getByTestId('design-setting-tabs').getByRole('tab', {name: 'Theme'}).click();
await modal.getByLabel('Email signup text').fill('test'); await modal.getByLabel('Email signup text').fill('test');
@ -182,14 +182,14 @@ test.describe('Design settings', async () => {
const modal = page.getByTestId('design-modal'); const modal = page.getByTestId('design-modal');
await modal.getByRole('tab', {name: 'Theme settings'}).click(); await modal.getByRole('tab', {name: 'Theme'}).click();
await chooseOptionInSelect(modal.getByTestId('setting-select-navigation_layout'), 'Logo in the middle'); await chooseOptionInSelect(modal.getByTestId('setting-select-navigation_layout'), 'Logo in the middle');
const expectedSettings = {navigation_layout: 'Logo in the middle'}; const expectedSettings = {navigation_layout: 'Logo in the middle'};
const expectedEncoded = new URLSearchParams([['custom', JSON.stringify(expectedSettings)]]).toString(); const expectedEncoded = new URLSearchParams([['custom', JSON.stringify(expectedSettings)]]).toString();
const matchingHeader = previewRequests.find(header => new RegExp(`&${expectedEncoded.replace(/\+/g, '\\+')}`).test(header)); const matchingHeader = previewRequests.find(header => new RegExp(`&${expectedEncoded.replace(/\+/g, '\\+')}`).test(header));
expect(matchingHeader).toBeDefined(); expect(matchingHeader).toBeDefined();
await modal.getByRole('button', {name: 'Save'}).click(); await modal.getByRole('button', {name: 'Save'}).click();
expect(lastApiRequests.editCustomThemeSettings?.body).toMatchObject({ expect(lastApiRequests.editCustomThemeSettings?.body).toMatchObject({
@ -230,8 +230,8 @@ test.describe('Design settings', async () => {
const designSettingTabs = modal.getByTestId('design-setting-tabs'); const designSettingTabs = modal.getByTestId('design-setting-tabs');
await expect(designSettingTabs.getByRole('tab', {name: 'Global'})).toBeHidden(); await expect(designSettingTabs.getByRole('tab', {name: 'Brand'})).toBeHidden();
await expect(designSettingTabs.getByRole('tab', {name: 'Theme settings'})).toBeHidden(); await expect(designSettingTabs.getByRole('tab', {name: 'Theme'})).toBeHidden();
await expect(designSettingTabs.getByTestId('accent-color-picker')).toBeVisible(); await expect(designSettingTabs.getByTestId('accent-color-picker')).toBeVisible();
}); });
@ -277,7 +277,7 @@ test.describe('Design settings', async () => {
const modal = page.getByTestId('design-modal'); const modal = page.getByTestId('design-modal');
await modal.getByRole('tab', {name: 'Theme settings'}).click(); await modal.getByRole('tab', {name: 'Theme'}).click();
const showFeaturedPostsCustomThemeSetting = modal.getByLabel('Show featured posts'); const showFeaturedPostsCustomThemeSetting = modal.getByLabel('Show featured posts');