diff --git a/docs-ui/src/components/StickyHeader/StickyHeader.module.css b/docs-ui/src/components/StickyHeader/StickyHeader.module.css
index 783b4a55be..7cfc197f83 100644
--- a/docs-ui/src/components/StickyHeader/StickyHeader.module.css
+++ b/docs-ui/src/components/StickyHeader/StickyHeader.module.css
@@ -57,16 +57,22 @@
.versionLinks {
display: flex;
align-items: center;
- gap: 12px;
-}
-.versionLinks a {
- color: var(--text-secondary);
- transition: color 0.2s ease;
-}
+ a {
+ width: 48px;
+ height: 48px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: var(--secondary);
+ transition: color 0.2s ease-in-out, background-color 0.2s ease-in-out;
+ border-radius: 48px;
-.versionLinks a:hover {
- color: var(--text-primary);
+ &:hover {
+ color: var(--primary);
+ background-color: var(--action);
+ }
+ }
}
@media (max-width: 768px) {
diff --git a/docs-ui/src/components/Toolbar/Toolbar.module.css b/docs-ui/src/components/Toolbar/Toolbar.module.css
index 5e3fe70808..f0e58f2edb 100644
--- a/docs-ui/src/components/Toolbar/Toolbar.module.css
+++ b/docs-ui/src/components/Toolbar/Toolbar.module.css
@@ -78,7 +78,8 @@
display: flex;
align-items: center;
justify-content: center;
- background-color: var(--action);
+ /* background-color: var(--action); */
+ border: 1px solid var(--border2);
border-radius: 48px;
padding-inline: 20px;
color: var(--primary);
diff --git a/docs-ui/src/content/components/header-page.mdx b/docs-ui/src/content/components/header-page.mdx
new file mode 100644
index 0000000000..4589e037a4
--- /dev/null
+++ b/docs-ui/src/content/components/header-page.mdx
@@ -0,0 +1,40 @@
+import { PropsTable } from '@/components/PropsTable';
+import { CodeBlock } from '@/components/CodeBlock';
+import { Snippet } from '@/components/Snippet';
+import { HeaderPageSnippet } from '@/snippets/stories-snippets';
+import {
+ propDefs,
+ usage,
+ simple,
+ defaultSnippet,
+ withTabs,
+ withBreadcrumbs,
+ withHeaderPage,
+} from './header-page.props';
+import { PageTitle } from '@/components/PageTitle';
+import { Theming } from '@/components/Theming';
+import { ChangelogComponent } from '@/components/ChangelogComponent';
+
+
+
+}
+ code={defaultSnippet}
+/>
+
+## Usage
+
+
+
+## API reference
+
+
+
+
+
+
diff --git a/docs-ui/src/content/components/header-page.props.ts b/docs-ui/src/content/components/header-page.props.ts
new file mode 100644
index 0000000000..d287c8baf8
--- /dev/null
+++ b/docs-ui/src/content/components/header-page.props.ts
@@ -0,0 +1,91 @@
+import {
+ childrenPropDefs,
+ classNamePropDefs,
+ stylePropDefs,
+ type PropDef,
+} from '@/utils/propDefs';
+
+export const propDefs: Record = {
+ title: {
+ type: 'string',
+ default: 'Your plugin',
+ },
+ customActions: {
+ type: 'enum',
+ values: ['ReactNode'],
+ },
+ menuItems: {
+ type: 'complex',
+ complexType: {
+ name: 'MenuItem[]',
+ properties: {
+ label: {
+ type: 'string',
+ required: true,
+ description: 'Display text for the menu item',
+ },
+ value: {
+ type: 'string',
+ required: true,
+ description: 'Unique value for the menu item',
+ },
+ onClick: {
+ type: '() => void',
+ required: false,
+ description: 'Callback function when menu item is clicked',
+ },
+ },
+ },
+ },
+ tabs: {
+ type: 'complex',
+ complexType: {
+ name: 'HeaderTab[]',
+ properties: {
+ id: {
+ type: 'string',
+ required: true,
+ description: 'Unique identifier for the tab',
+ },
+ label: {
+ type: 'string',
+ required: true,
+ description: 'Display text for the tab',
+ },
+ href: {
+ type: 'string',
+ required: false,
+ description: 'URL to navigate to when tab is clicked',
+ },
+ matchStrategy: {
+ type: "'exact' | 'prefix'",
+ required: false,
+ description: 'How to match the current route to highlight the tab',
+ },
+ },
+ },
+ },
+ ...childrenPropDefs,
+ ...classNamePropDefs,
+ ...stylePropDefs,
+};
+
+export const usage = `import { HeaderPage } from '@backstage/ui';
+
+`;
+
+export const defaultSnippet = `Custom action}
+/>`;
diff --git a/docs-ui/src/content/components/header.mdx b/docs-ui/src/content/components/header.mdx
index d59dd79613..af4e8010c5 100644
--- a/docs-ui/src/content/components/header.mdx
+++ b/docs-ui/src/content/components/header.mdx
@@ -4,16 +4,13 @@ import { Snippet } from '@/components/Snippet';
import { HeaderSnippet } from '@/snippets/stories-snippets';
import {
propDefs,
- flexUsageSnippet,
- flexDefaultSnippet,
- flexFAQ1Snippet,
- flexSimpleSnippet,
- flexResponsiveSnippet,
- flexAlignSnippet,
usage,
+ simple,
defaultSnippet,
+ withTabs,
+ withBreadcrumbs,
+ withHeaderPage,
} from './header.props';
-import { spacingPropDefs } from '@/utils/propDefs';
import { PageTitle } from '@/components/PageTitle';
import { Theming } from '@/components/Theming';
import { ChangelogComponent } from '@/components/ChangelogComponent';
@@ -26,7 +23,7 @@ import { ChangelogComponent } from '@/components/ChangelogComponent';
}
+ preview={}
code={defaultSnippet}
/>
@@ -38,31 +35,50 @@ import { ChangelogComponent } from '@/components/ChangelogComponent';
-The grid component also accepts all the spacing props from the Box component.
-
-
-
## Examples
-### Simple
+### Simple header
-A simple example of how to use the Flex component.
+A simple example of how to use the Header component.
-
+}
+ code={simple}
+ open
+/>
-### Responsive
+### Header with tabs
-The Flex component also supports responsive values, making it easy to create
-responsive designs.
+A simple example of how to use the Header component with tabs. All links are using React Router
+under the hood and will be active when you are on the corresponding page.
-
+}
+code={withTabs}
+open
+/>
-The Flex component also supports responsive alignment, making it easy to
-create responsive designs.
+### Header with breadcrumbs
-
+Breacrumbs should appear when you scroll down (and not directly visible as it is in the demo below).
+
+}
+ code={withBreadcrumbs}
+ open
+/>
+
+### Header with HeaderPage
+
+You can use the `Header` component inside the [HeaderPage](/components/header-page) component to compose your multi-level navigation.
+
+}
+ code={withHeaderPage}
+ open
+/>
diff --git a/docs-ui/src/content/components/header.props.ts b/docs-ui/src/content/components/header.props.ts
index ee22fb7d67..50c5540153 100644
--- a/docs-ui/src/content/components/header.props.ts
+++ b/docs-ui/src/content/components/header.props.ts
@@ -91,6 +91,10 @@ export const propDefs: Record = {
},
},
},
+ onTabSelectionChange: {
+ type: 'enum',
+ values: ['(key: string) => void'],
+ },
...childrenPropDefs,
...classNamePropDefs,
...stylePropDefs,
@@ -128,20 +132,87 @@ export const defaultSnippet = ``;
-export const flexSimpleSnippet = `
- Hello World
- Hello World
- Hello World
-`;
+export const simple = `
+ } />
+ } />
+ } />
+ >
+ }
+/>`;
-export const flexResponsiveSnippet = `
- Hello World
- Hello World
- Hello World
-`;
+export const withTabs = `
+
+ } />
+ } />
+ } />
+ >
+ }
+ tabs={[
+ { id: 'overview', label: 'Overview' },
+ { id: 'checks', label: 'Checks' },
+ { id: 'tracks', label: 'Tracks' },
+ { id: 'campaigns', label: 'Campaigns' },
+ { id: 'integrations', label: 'Integrations' },
+ ]}
+/>
+`;
-export const flexAlignSnippet = `
- Hello World
- Hello World
- Hello World
-`;
+export const withBreadcrumbs = ``;
+
+export const withHeaderPage = `
+Custom action}
+/>`;
diff --git a/docs-ui/src/css/globals.css b/docs-ui/src/css/globals.css
index 9193f49b5a..69a2c8ddfe 100644
--- a/docs-ui/src/css/globals.css
+++ b/docs-ui/src/css/globals.css
@@ -13,6 +13,7 @@
--font-weight-regular: 400;
--font-weight-bold: 600;
--border: #e5e5e5;
+ --border2: #cdcdcd;
--surface-1: #f4f4f4;
}
@@ -24,6 +25,7 @@
--action: #202020;
--link: #4856e8;
--border: #2a2a2a;
+ --border2: #2a2a2a;
--surface-1: #282828;
}
diff --git a/docs-ui/src/utils/data.ts b/docs-ui/src/utils/data.ts
index 326ecd5aa5..348f4df24e 100644
--- a/docs-ui/src/utils/data.ts
+++ b/docs-ui/src/utils/data.ts
@@ -106,6 +106,11 @@ export const components: Page[] = [
slug: 'header',
status: 'alpha',
},
+ {
+ title: 'HeaderPage',
+ slug: 'header-page',
+ status: 'alpha',
+ },
{
title: 'Icon',
slug: 'icon',
diff --git a/packages/ui/src/components/Header/Header.stories.tsx b/packages/ui/src/components/Header/Header.stories.tsx
index 7d58aad1de..302aef9765 100644
--- a/packages/ui/src/components/Header/Header.stories.tsx
+++ b/packages/ui/src/components/Header/Header.stories.tsx
@@ -169,30 +169,7 @@ export const WithOptions: Story = {
};
export const WithCustomActions: Story = {
- args: {
- menuItems,
- },
- decorators: [withRouter],
- render: args => (
- Custom action} />
- ),
-};
-
-export const WithBreadcrumbs: Story = {
- args: {
- breadcrumbs,
- },
- decorators: [withRouter],
-};
-
-export const WithAllComponents: Story = {
- args: {
- title: 'My plugin',
- titleLink: '/',
- menuItems,
- tabs,
- breadcrumbs,
- },
+ args: {},
decorators: [withRouter],
render: args => (
(
+ <>
+
+ } />
+ } />
+ } />
+ >
+ }
+ />
+ Custom action}
+ />
+ >
+ ),
+};
+
export const WithLayout: Story = {
args: {
menuItems,