0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-24 23:48:13 -05:00

Added simple search bar to AdminX settings

refs https://github.com/TryGhost/Team/issues/3349
This commit is contained in:
Jono Mingard 2023-06-21 22:11:55 +10:00
parent 543f3750a7
commit dd1d2f8d4d
21 changed files with 58 additions and 8 deletions

View file

@ -1,6 +1,8 @@
import ButtonGroup from '../global/ButtonGroup';
import React from 'react';
import SettingGroupHeader from './SettingGroupHeader';
import clsx from 'clsx';
import useSearchable from '../../hooks/useSearchable';
import {ButtonProps} from '../global/Button';
import {SaveState} from '../../hooks/useForm';
@ -9,6 +11,7 @@ interface SettingGroupProps {
testId?: string;
title?: string;
description?: React.ReactNode;
searchKeywords?: string[];
isEditing?: boolean;
saveState?: SaveState;
customHeader?: React.ReactNode;
@ -36,6 +39,7 @@ const SettingGroup: React.FC<SettingGroupProps> = ({
testId,
title,
description,
searchKeywords,
isEditing,
saveState,
customHeader,
@ -49,6 +53,8 @@ const SettingGroup: React.FC<SettingGroupProps> = ({
onSave,
onCancel
}) => {
const {isVisible} = useSearchable({keywords: searchKeywords && [title || '', ...searchKeywords]});
const handleEdit = () => {
onEditingChange?.(true);
};
@ -120,7 +126,7 @@ const SettingGroup: React.FC<SettingGroupProps> = ({
}
return (
<div className={`relative flex flex-col gap-6 rounded ${border && 'border p-5 md:p-7'} ${styles}`} data-testid={testId}>
<div className={clsx('relative flex flex-col gap-6 rounded', !isVisible && 'hidden', border && 'border p-5 md:p-7', styles)} data-testid={testId}>
<div className='absolute top-[-60px]' id={navid && navid}></div>
{customHeader ? customHeader :
<SettingGroupHeader description={description} title={title!}>

View file

@ -8,14 +8,14 @@ interface Props {
const SettingSection: React.FC<Props> = ({title, children}) => {
return (
<>
<div className="!visible hidden [&:has(>div>:not(.hidden))]:!block">
{title && <SettingSectionHeader sticky={true} title={title} />}
{children &&
<div className="mb-[100px] flex flex-col gap-9">
{children}
</div>
}
</>
</div>
);
};

View file

@ -1,8 +1,12 @@
import React from 'react';
import SettingNavItem from '../admin-x-ds/settings/SettingNavItem';
import SettingNavSection from '../admin-x-ds/settings/SettingNavSection';
import TextField from '../admin-x-ds/global/form/TextField';
import {useSearch} from './providers/ServiceProvider';
const Sidebar: React.FC = () => {
const {filter, setFilter} = useSearch();
const handleSectionClick = (e: React.MouseEvent<HTMLButtonElement>) => {
const element = document.getElementById(e.currentTarget.name);
if (element) {
@ -12,6 +16,8 @@ const Sidebar: React.FC = () => {
return (
<div className="hidden md:!visible md:!block md:h-[calc(100vh-5vmin-84px)] md:w-[300px] md:overflow-y-scroll md:pt-[32px]">
<TextField containerClassName="mb-10" placeholder="Search" value={filter} onChange={e => setFilter(e.target.value)} />
<SettingNavSection title="General">
<SettingNavItem navid='title-and-description' title="Title and description" onClick={handleSectionClick} />
<SettingNavItem navid='timezone' title="Timezone" onClick={handleSectionClick} />

View file

@ -9,6 +9,7 @@ interface ServicesContextProps {
api: ReturnType<typeof setupGhostApi>;
fileService: FileService|null;
officialThemes: OfficialTheme[];
search: {filter: string, setFilter: (value: string) => void}
}
interface ServicesProviderProps {
@ -20,7 +21,8 @@ interface ServicesProviderProps {
const ServicesContext = createContext<ServicesContextProps>({
api: setupGhostApi({ghostVersion: ''}),
fileService: null,
officialThemes: []
officialThemes: [],
search: {filter: '', setFilter: () => {}}
});
const ServicesProvider: React.FC<ServicesProviderProps> = ({children, ghostVersion, officialThemes}) => {
@ -32,11 +34,14 @@ const ServicesProvider: React.FC<ServicesProviderProps> = ({children, ghostVersi
}
}), [apiService]);
const [filter, setFilter] = React.useState('');
return (
<ServicesContext.Provider value={{
api: apiService,
fileService,
officialThemes
officialThemes,
search: {filter, setFilter}
}}>
{children}
</ServicesContext.Provider>
@ -50,3 +55,5 @@ export const useServices = () => useContext(ServicesContext);
export const useApi = () => useServices().api;
export const useOfficialThemes = () => useServices().officialThemes;
export const useSearch = () => useServices().search;

View file

@ -195,6 +195,7 @@ const DefaultRecipients: React.FC = () => {
isEditing={isEditing}
navid='default-recipients'
saveState={saveState}
searchKeywords={['newsletter', 'recipients', 'email']}
testId='default-recipients'
title='Default recipients'
onCancel={handleCancel}

View file

@ -101,6 +101,7 @@ const MailGun: React.FC = () => {
isEditing={isEditing}
navid='mailgun'
saveState={saveState}
searchKeywords={['mailgun', 'email']}
testId='mailgun'
title='Mailgun'
onCancel={handleCancel}

View file

@ -102,6 +102,7 @@ const Facebook: React.FC = () => {
isEditing={isEditing}
navid='facebook'
saveState={saveState}
searchKeywords={['facebook card', 'structured data', 'rich cards']}
testId='facebook'
title='Facebook card'
onCancel={handleCancel}

View file

@ -83,6 +83,7 @@ const LockSite: React.FC = () => {
isEditing={isEditing}
navid='locksite'
saveState={saveState}
searchKeywords={['private', 'password', 'lock']}
testId='locksite'
title='Make site private'
onCancel={handleCancel}

View file

@ -104,6 +104,7 @@ const Metadata: React.FC = () => {
isEditing={isEditing}
navid='metadata'
saveState={saveState}
searchKeywords={['meta', 'title', 'description', 'search', 'engine', 'google']}
testId='metadata'
title='Metadata'
onCancel={handleCancel}

View file

@ -59,6 +59,7 @@ const PublicationLanguage: React.FC = () => {
isEditing={isEditing}
navid='publication-language'
saveState={saveState}
searchKeywords={['language', 'locale']}
testId='publication-language'
title="Publication Language"
onCancel={handleCancel}

View file

@ -160,6 +160,7 @@ const SocialAccounts: React.FC = () => {
isEditing={isEditing}
navid='social-accounts'
saveState={saveState}
searchKeywords={['social', 'accounts', 'facebook', 'twitter', 'structured data', 'rich cards']}
testId='social-accounts'
title='Social accounts'
onCancel={handleCancel}

View file

@ -87,6 +87,7 @@ const TimeZone: React.FC = () => {
isEditing={isEditing}
navid='timezone'
saveState={saveState}
searchKeywords={['time', 'date', 'timezone', 'time zone']}
testId='timezone'
title='Site timezone'
onCancel={handleCancel}

View file

@ -71,6 +71,7 @@ const TitleAndDescription: React.FC = () => {
isEditing={isEditing}
navid='title-and-description'
saveState={saveState}
searchKeywords={['site title', 'site description']}
testId='title-and-description'
title='Title & description'
onCancel={handleCancel}

View file

@ -104,6 +104,7 @@ const Twitter: React.FC = () => {
isEditing={isEditing}
navid='twitter'
saveState={saveState}
searchKeywords={['twitter card', 'structured data', 'rich cards']}
testId='twitter'
title='Twitter card'
onCancel={handleCancel}

View file

@ -231,6 +231,7 @@ const Users: React.FC = () => {
<SettingGroup
customButtons={buttons}
navid='users'
searchKeywords={['users', 'permissions', 'roles', 'staff']}
title='Users and permissions'
>
<Owner updateUser={updateUser} user={ownerUser} />

View file

@ -145,6 +145,7 @@ const Access: React.FC = () => {
isEditing={isEditing}
navid='access'
saveState={saveState}
searchKeywords={['access', 'subscription', 'post']}
testId='access'
title='Access'
onCancel={handleCancel}

View file

@ -78,6 +78,7 @@ const Analytics: React.FC = () => {
isEditing={isEditing}
navid='analytics'
saveState={saveState}
searchKeywords={['analytics', 'tracking', 'privacy']}
testId='analytics'
title='Analytics'
onCancel={handleCancel}

View file

@ -14,6 +14,7 @@ const DesignSetting: React.FC = () => {
customButtons={<Button color='green' label='Customize' link onClick={openPreviewModal}/>}
description="Customize the look and feel of your site"
navid='branding-and-design'
searchKeywords={['design', 'branding', 'logo', 'cover', 'colors', 'fonts', 'background']}
testId='design'
title="Branding and design"
/>

View file

@ -14,6 +14,7 @@ const Navigation: React.FC = () => {
customButtons={<Button color='green' label='Customize' link onClick={openPreviewModal}/>}
description="Set up primary and secondary menus"
navid='navigation'
searchKeywords={['navigation', 'menus', 'primary', 'secondary', 'links']}
testId='navigation'
title="Navigation"
/>

View file

@ -12,6 +12,7 @@ const Theme: React.FC = () => {
}}/>}
description="Change or upload themes"
navid='theme'
searchKeywords={['themes', 'design', 'appearance', 'style']}
testId='theme'
title="Theme"
/>

View file

@ -0,0 +1,15 @@
import {useSearch} from '../components/providers/ServiceProvider';
const useSearchable = ({keywords}: { keywords: string[] | undefined }) => {
const {filter} = useSearch();
if (!filter || !keywords) {
return {isVisible: true};
}
const isVisible = keywords.some(keyword => keyword.toLowerCase().includes(filter.toLowerCase()));
return {isVisible};
};
export default useSearchable;