fix(ui): adjust plugin header spacing
Align PluginHeader spacing across tabbed and non-tabbed variants so the component owns the surrounding page spacing more consistently. Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/ui': patch
|
||||
---
|
||||
|
||||
Adjusted PluginHeader spacing so headers with and without tabs align more consistently with surrounding page content.
|
||||
|
||||
**Affected components:** PluginHeader, Header
|
||||
@@ -245,11 +245,12 @@
|
||||
* this file for easier scanning alongside other component overrides above.
|
||||
*/
|
||||
[data-theme-name='spotify'] {
|
||||
.bui-PluginHeader {
|
||||
margin-top: var(--bui-space-4);
|
||||
}
|
||||
|
||||
.bui-PluginHeaderToolbar {
|
||||
height: 32px;
|
||||
border: none;
|
||||
background: none;
|
||||
margin-top: var(--bui-space-4);
|
||||
}
|
||||
|
||||
.bui-PluginHeaderTabsWrapper {
|
||||
@@ -258,8 +259,4 @@
|
||||
margin-left: 0;
|
||||
margin-top: var(--bui-space-2);
|
||||
}
|
||||
|
||||
.bui-HeaderTop {
|
||||
padding-top: var(--bui-space-4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,10 +32,6 @@
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.bui-HeaderTop {
|
||||
padding-top: var(--bui-space-6);
|
||||
}
|
||||
|
||||
.bui-HeaderStickySentinel {
|
||||
height: 1px;
|
||||
margin-bottom: -1px;
|
||||
|
||||
@@ -17,15 +17,23 @@
|
||||
@layer tokens, base, components, utilities;
|
||||
|
||||
@layer components {
|
||||
.bui-PluginHeader {
|
||||
margin-bottom: var(--bui-space-6);
|
||||
padding-inline: var(--bui-space-5);
|
||||
}
|
||||
|
||||
.bui-PluginHeaderToolbar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-inline: var(--bui-space-5);
|
||||
color: var(--bui-fg-primary);
|
||||
height: 52px;
|
||||
border-bottom: 1px solid var(--bui-border-1);
|
||||
border-bottom: solid 1px var(--bui-border-1);
|
||||
|
||||
&[data-has-tabs] {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.bui-PluginHeaderToolbarContent {
|
||||
@@ -69,7 +77,6 @@
|
||||
}
|
||||
|
||||
.bui-PluginHeaderTabsWrapper {
|
||||
padding-inline: var(--bui-space-3);
|
||||
border-bottom: 1px solid var(--bui-border-1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import { Box } from '../Box';
|
||||
import { Link } from '../Link';
|
||||
import { RiShapesLine } from '@remixicon/react';
|
||||
import { Text } from '../Text';
|
||||
import { BgReset } from '../../hooks/useBg';
|
||||
|
||||
declare module 'react-aria-components' {
|
||||
interface RouterConfig {
|
||||
@@ -53,7 +52,7 @@ export const PluginHeader = (props: PluginHeaderProps) => {
|
||||
} = ownProps;
|
||||
|
||||
const hasTabs = tabs && tabs.length > 0;
|
||||
const headerRef = useRef<HTMLElement>(null);
|
||||
const rootRef = useRef<HTMLDivElement>(null);
|
||||
const animationFrameRef = useRef<number | undefined>(undefined);
|
||||
const lastAppliedHeightRef = useRef<number | undefined>(undefined);
|
||||
|
||||
@@ -62,7 +61,7 @@ export const PluginHeader = (props: PluginHeaderProps) => {
|
||||
}, [customActions]);
|
||||
|
||||
useIsomorphicLayoutEffect(() => {
|
||||
const el = headerRef.current;
|
||||
const el = rootRef.current;
|
||||
if (!el) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -125,50 +124,44 @@ export const PluginHeader = (props: PluginHeaderProps) => {
|
||||
const titleText = title || 'Your plugin';
|
||||
|
||||
return (
|
||||
<BgReset>
|
||||
<header ref={headerRef} className={classes.root}>
|
||||
<Box bg="neutral" className={classes.toolbar} data-has-tabs={hasTabs}>
|
||||
<div className={classes.toolbarContent}>
|
||||
<Box
|
||||
bg="neutral"
|
||||
className={classes.toolbarIcon}
|
||||
aria-hidden="true"
|
||||
>
|
||||
{icon || <RiShapesLine />}
|
||||
</Box>
|
||||
<h1 className={classes.toolbarName}>
|
||||
{titleLink ? (
|
||||
<Link href={titleLink} standalone variant="body-medium">
|
||||
{titleText}
|
||||
</Link>
|
||||
) : (
|
||||
<Text as="span" variant="body-medium">
|
||||
{titleText}
|
||||
</Text>
|
||||
)}
|
||||
</h1>
|
||||
</div>
|
||||
<div className={classes.toolbarControls}>{actionChildren}</div>
|
||||
</Box>
|
||||
{tabs && (
|
||||
<Box bg="neutral" className={classes.tabs}>
|
||||
<Tabs onSelectionChange={onTabSelectionChange}>
|
||||
<TabList>
|
||||
{tabs?.map(tab => (
|
||||
<Tab
|
||||
key={tab.id}
|
||||
id={tab.id}
|
||||
href={tab.href}
|
||||
matchStrategy={tab.matchStrategy}
|
||||
>
|
||||
{tab.label}
|
||||
</Tab>
|
||||
))}
|
||||
</TabList>
|
||||
</Tabs>
|
||||
<div ref={rootRef} className={classes.root}>
|
||||
<div className={classes.toolbar} data-has-tabs={hasTabs}>
|
||||
<div className={classes.toolbarContent}>
|
||||
<Box bg="neutral" className={classes.toolbarIcon} aria-hidden="true">
|
||||
{icon || <RiShapesLine />}
|
||||
</Box>
|
||||
)}
|
||||
</header>
|
||||
</BgReset>
|
||||
<h1 className={classes.toolbarName}>
|
||||
{titleLink ? (
|
||||
<Link href={titleLink} standalone variant="body-medium">
|
||||
{titleText}
|
||||
</Link>
|
||||
) : (
|
||||
<Text as="span" variant="body-medium">
|
||||
{titleText}
|
||||
</Text>
|
||||
)}
|
||||
</h1>
|
||||
</div>
|
||||
<div className={classes.toolbarControls}>{actionChildren}</div>
|
||||
</div>
|
||||
{tabs && (
|
||||
<div className={classes.tabs}>
|
||||
<Tabs onSelectionChange={onTabSelectionChange}>
|
||||
<TabList>
|
||||
{tabs?.map(tab => (
|
||||
<Tab
|
||||
key={tab.id}
|
||||
id={tab.id}
|
||||
href={tab.href}
|
||||
matchStrategy={tab.matchStrategy}
|
||||
>
|
||||
{tab.label}
|
||||
</Tab>
|
||||
))}
|
||||
</TabList>
|
||||
</Tabs>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -49,7 +49,7 @@ import {
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const PageContent = () => (
|
||||
<Container mt="6">
|
||||
<Container>
|
||||
<Flex direction="row" gap="4">
|
||||
<Card style={{ minHeight: 120, flex: 1 }} />
|
||||
<Card style={{ minHeight: 120, flex: 1 }} />
|
||||
@@ -59,7 +59,7 @@ const PageContent = () => (
|
||||
);
|
||||
|
||||
const LongPageContent = () => (
|
||||
<Container mt="6" pb="3">
|
||||
<Container pb="3">
|
||||
<Flex direction="row" gap="4" mb="4">
|
||||
<Card style={{ minHeight: 200, flex: 1 }} />
|
||||
<Card style={{ minHeight: 200, flex: 1 }} />
|
||||
@@ -104,6 +104,28 @@ export const NoHeader = meta.story({
|
||||
),
|
||||
});
|
||||
|
||||
export const NoHeaderWithTabs = meta.story({
|
||||
decorators: [withLayout],
|
||||
render: () => (
|
||||
<>
|
||||
<PluginHeader
|
||||
icon={<RiCodeSSlashLine />}
|
||||
title="APIs"
|
||||
tabs={[
|
||||
{ id: 'overview', label: 'Overview', href: '/apis' },
|
||||
{
|
||||
id: 'definitions',
|
||||
label: 'Definitions',
|
||||
href: '/apis/definitions',
|
||||
},
|
||||
{ id: 'consumers', label: 'Consumers', href: '/apis/consumers' },
|
||||
]}
|
||||
/>
|
||||
<PageContent />
|
||||
</>
|
||||
),
|
||||
});
|
||||
|
||||
export const SimpleHeader = meta.story({
|
||||
decorators: [withLayout],
|
||||
render: () => (
|
||||
|
||||
Reference in New Issue
Block a user