-
Notifications
You must be signed in to change notification settings - Fork 858
Normalize admin page headers with unified AdminHeader wrapping @wordpress/admin-ui #47313
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
Changes from all commits
48e0231
a9c29d9
3a02926
d466425
26e75cd
e44672a
9c6bbac
3ed2b64
4c17294
8f91ee2
b6aa072
04f321e
2985c11
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| Significance: minor | ||
| Type: added | ||
|
|
||
| Add AdminHeader component wrapping @wordpress/admin-ui Page for unified admin page headers. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| /* Proxy file to import @wordpress/admin-ui styles. | ||
| * | ||
| * Importing the CSS via @import inside a .css file avoids the | ||
| * @wordpress/dependency-extraction-webpack-plugin externalization that | ||
| * breaks direct JS `import '@wordpress/admin-ui/build-style/style.css'`. | ||
| * css-loader resolves @import independently of the externals plugin. | ||
| */ | ||
| @import "@wordpress/admin-ui/build-style/style.css"; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| import { Page } from '@wordpress/admin-ui'; | ||
| import './admin-ui-styles.css'; | ||
| import { | ||
| __experimentalHeading as Heading, // eslint-disable-line @wordpress/no-unsafe-wp-apis | ||
| __experimentalHStack as HStack, // eslint-disable-line @wordpress/no-unsafe-wp-apis | ||
| } from '@wordpress/components'; | ||
| import JetpackLogo from '../jetpack-logo/index.tsx'; | ||
| import type { AdminHeaderProps } from './types.ts'; | ||
| import type { FC } from 'react'; | ||
|
|
||
| /** | ||
| * Unified admin page header component. | ||
| * | ||
| * Renders a sticky header with logo, product title, optional subtitle, | ||
| * actions, and tabs. Wraps the `@wordpress/admin-ui` Page component. | ||
| * | ||
| * @param {AdminHeaderProps} props - Component properties. | ||
| * @return {ReactNode} AdminHeader component. | ||
| */ | ||
| const AdminHeader: FC< AdminHeaderProps > = ( { | ||
| logo, | ||
| title, | ||
| subTitle, | ||
| actions, | ||
| tabs = null, | ||
| className, | ||
| breadcrumbs = null, | ||
| badges = null, | ||
| } ) => { | ||
| const classes = className; | ||
|
|
||
| // While admin-ui Page has a title prop, it fails to render both the logo and | ||
| // text. Internally it tries to accommodate both inside Heading. | ||
| // Composing here with Heading as it is on admin-ui Page. | ||
| const composedTitle = title ? ( | ||
| <HStack spacing={ 2 } justify="left"> | ||
| { logo || <JetpackLogo showText={ false } height={ 20 } /> } | ||
| <Heading as="h2" level={ 3 } weight={ 500 } truncate> | ||
| { title } | ||
| </Heading> | ||
| </HStack> | ||
| ) : undefined; | ||
|
|
||
| return ( | ||
| <Page | ||
| className={ classes } | ||
| title={ composedTitle } | ||
| subTitle={ subTitle } | ||
| actions={ actions } | ||
| breadcrumbs={ breadcrumbs } | ||
| badges={ badges } | ||
| showSidebarToggle={ false } | ||
| > | ||
| { tabs } | ||
| </Page> | ||
| ); | ||
|
Comment on lines
+44
to
+56
|
||
| }; | ||
|
|
||
| export default AdminHeader; | ||
|
Comment on lines
+20
to
+59
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| import type { ReactNode } from 'react'; | ||
|
|
||
| export type AdminHeaderProps = { | ||
| /** | ||
| * Custom logo element. Defaults to JetpackLogo icon (bolt only). | ||
| */ | ||
| logo?: ReactNode; | ||
|
|
||
| /** | ||
| * Product title displayed next to the logo. | ||
| */ | ||
| title: string; | ||
|
|
||
| /** | ||
| * Optional subtitle displayed below the title row. | ||
| */ | ||
| subTitle?: string; | ||
|
|
||
| /** | ||
| * Optional breadcrumb elements displayed next to the title. | ||
| */ | ||
| breadcrumbs?: ReactNode; | ||
|
|
||
| /** | ||
| * Optional badge elements displayed next to the title. | ||
| */ | ||
| badges?: ReactNode; | ||
|
|
||
| /** | ||
| * Optional action elements (buttons, links) displayed on the right side of the header. | ||
| */ | ||
| actions?: ReactNode; | ||
|
|
||
| /** | ||
| * Optional tab navigation displayed below the title/tagline. | ||
| */ | ||
| tabs?: ReactNode; | ||
|
|
||
| /** | ||
| * Additional CSS class name. | ||
| */ | ||
| className?: string; | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,10 +18,37 @@ export type AdminPageProps = { | |
| showHeader?: boolean; | ||
|
|
||
| /** | ||
| * Custom header. Optional | ||
| * Custom header. Optional. | ||
| * @deprecated Use `title` and `subTitle` props instead for the unified header. | ||
| */ | ||
| header?: ReactNode; | ||
|
|
||
| /** | ||
| * Product title displayed in the unified header (e.g. "Social", "Backup"). | ||
| * When provided, renders the new AdminHeader instead of the legacy header slot. | ||
| */ | ||
| title?: string; | ||
|
|
||
| /** | ||
| * Optional tagline displayed below the title in the unified header. | ||
| */ | ||
| subTitle?: string; | ||
|
|
||
| /** | ||
| * Custom logo element for the unified header. Defaults to JetpackLogo icon. | ||
| */ | ||
| logo?: ReactNode; | ||
|
|
||
| /** | ||
| * Action elements displayed on the right side of the unified header. | ||
| */ | ||
| actions?: ReactNode; | ||
|
|
||
| /** | ||
| * Tab navigation displayed below the title/tagline in the unified header. | ||
| */ | ||
| tabs?: ReactNode; | ||
|
||
|
|
||
| /** | ||
| * Whether or not to display the Footer | ||
| */ | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -34,6 +34,8 @@ export { default as NumberSlider } from './components/number-slider/index.tsx'; | |||||||
| export { default as AdminSection } from './components/admin-section/basic/index.tsx'; | ||||||||
| export { default as AdminSectionHero } from './components/admin-section/hero/index.tsx'; | ||||||||
| export { default as AdminPage } from './components/admin-page/index.tsx'; | ||||||||
| export { default as AdminHeader } from './components/admin-header/index.tsx'; | ||||||||
|
||||||||
| export { default as AdminHeader } from './components/admin-header/index.tsx'; | |
| export { default as AdminHeader } from './components/admin-header/index.tsx'; | |
| export type { AdminHeaderProps } from './components/admin-header/types.ts'; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,20 +8,21 @@ import { | |
| } from '@automattic/jetpack-components'; | ||
| import { useConnection } from '@automattic/jetpack-connection'; | ||
| import { | ||
| getMyJetpackUrl, | ||
| isJetpackSelfHostedSite, | ||
| isSimpleSite, | ||
| siteHasFeature, | ||
| currentUserCan, | ||
| } from '@automattic/jetpack-script-data'; | ||
| import { shouldUseInternalLinks } from '@automattic/jetpack-shared-extension-utils'; | ||
| import { useSelect } from '@wordpress/data'; | ||
| import { useState, useCallback } from '@wordpress/element'; | ||
| import { createInterpolateElement, useState, useCallback } from '@wordpress/element'; | ||
| import { __ } from '@wordpress/i18n'; | ||
| import { store as socialStore } from '../../social-store'; | ||
| import { features, getSocialScriptData, hasSocialPaidFeatures } from '../../utils'; | ||
| import ConnectionScreen from './connection-screen'; | ||
| import Header from './header'; | ||
| import InfoSection from './info-section'; | ||
| import AdminPageHeader from './page-header'; | ||
| import './styles.module.scss'; | ||
| import PricingPage from './pricing-page'; | ||
| import SupportSection from './support-section'; | ||
|
|
@@ -65,7 +66,8 @@ export const SocialAdminPage = () => { | |
| return ( | ||
| <AdminPage | ||
| moduleName={ moduleName } | ||
| showHeader={ false } | ||
| title={ __( 'Social', 'jetpack-publicize-pkg' ) } | ||
| subTitle={ __( 'Publish once. Share everywhere.', 'jetpack-publicize-pkg' ) } | ||
| showBackground={ false } | ||
| useInternalLinks={ shouldUseInternalLinks() } | ||
| > | ||
|
|
@@ -78,10 +80,25 @@ export const SocialAdminPage = () => { | |
| ); | ||
| } | ||
|
|
||
| const licenseAction = | ||
| ! hasSocialPaidFeatures() && isJetpackSite | ||
| ? createInterpolateElement( | ||
| __( | ||
| 'Already have an existing plan or license key? <a>Click here to get started</a>', | ||
| 'jetpack-publicize-pkg' | ||
| ), | ||
| { | ||
| a: <a href={ getMyJetpackUrl( '#/add-license' ) } />, | ||
| } | ||
| ) | ||
| : null; | ||
|
Comment on lines
+83
to
+94
|
||
|
|
||
| return ( | ||
| <AdminPage | ||
| moduleName={ moduleName } | ||
| header={ <AdminPageHeader /> } | ||
| title={ __( 'Social', 'jetpack-publicize-pkg' ) } | ||
| subTitle={ __( 'Publish once. Share everywhere.', 'jetpack-publicize-pkg' ) } | ||
| actions={ licenseAction } | ||
| showFooter={ isJetpackSite } | ||
| useInternalLinks={ shouldUseInternalLinks() } | ||
| > | ||
|
|
||
This file was deleted.
This file was deleted.
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The HStack uses
justify="left", but the codebase more commonly usesjustify="start"for left alignment (see examples in forms/routes/responses/integrations-modal.tsx:184, forms/src/blocks/contact-form/components/jetpack-integrations-modal/helpers/akismet.tsx:76, and many others). While both work, usingjustify="start"would be more consistent with the rest of the codebase.