From 2329cb09e563334afc20bade89f0e6408abc8013 Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Tue, 22 Jul 2025 15:08:50 +0100 Subject: [PATCH 1/7] Improve docs header Signed-off-by: Charles de Dreuille --- docs-ui/src/app/layout.tsx | 6 +- .../src/components/Sidebar/Sidebar.module.css | 31 +---- docs-ui/src/components/Sidebar/index.tsx | 16 +-- .../StickyHeader/StickyHeader.module.css | 92 +++++++++++++++ .../components/StickyHeader/StickyHeader.tsx | 50 ++++++++ docs-ui/src/components/Toolbar/Logo.tsx | 20 ++++ .../src/components/Toolbar/Toolbar.module.css | 75 ++++++++++-- docs-ui/src/components/Toolbar/Toolbar.tsx | 59 +++++++--- .../components/Toolbar/theme-name.module.css | 109 +++++++----------- docs-ui/src/components/Toolbar/theme-name.tsx | 55 ++++----- docs-ui/src/css/globals.css | 2 +- docs-ui/src/hooks/useCurrentPage.ts | 31 +++++ docs-ui/src/utils/getPageName.ts | 29 +++++ 13 files changed, 401 insertions(+), 174 deletions(-) create mode 100644 docs-ui/src/components/StickyHeader/StickyHeader.module.css create mode 100644 docs-ui/src/components/StickyHeader/StickyHeader.tsx create mode 100644 docs-ui/src/components/Toolbar/Logo.tsx create mode 100644 docs-ui/src/hooks/useCurrentPage.ts create mode 100644 docs-ui/src/utils/getPageName.ts diff --git a/docs-ui/src/app/layout.tsx b/docs-ui/src/app/layout.tsx index 58decbf22b..d90f1c06a4 100644 --- a/docs-ui/src/app/layout.tsx +++ b/docs-ui/src/app/layout.tsx @@ -1,6 +1,7 @@ import type { Metadata } from 'next'; import { Sidebar } from '../components/Sidebar'; import { Toolbar } from '@/components/Toolbar'; +import { StickyHeader } from '../components/StickyHeader/StickyHeader'; import { Providers } from './providers'; import { CustomTheme } from '@/components/CustomTheme'; import styles from './layout.module.css'; @@ -49,8 +50,9 @@ export default async function RootLayout({ > - - + + +
{children}
diff --git a/docs-ui/src/components/Sidebar/Sidebar.module.css b/docs-ui/src/components/Sidebar/Sidebar.module.css index 2b88945c47..75ac541d9f 100644 --- a/docs-ui/src/components/Sidebar/Sidebar.module.css +++ b/docs-ui/src/components/Sidebar/Sidebar.module.css @@ -15,33 +15,6 @@ } } -.version { - font-size: 0.875rem; - font-weight: 500; - color: var(--secondary); - margin-inline: 32px; - border-bottom: 1px solid var(--border); - padding-bottom: 12px; - display: flex; - align-items: center; - justify-content: space-between; -} - -.versionLinks { - display: flex; - align-items: center; - gap: 8px; - - a { - color: var(--secondary); - transition: color 0.2s ease-in-out; - - &:hover { - color: var(--primary); - } - } -} - .root { height: 100%; } @@ -106,6 +79,10 @@ color: var(--secondary); margin-top: 40px; text-transform: uppercase; + + &:first-child { + margin-top: 12px; + } } .line { diff --git a/docs-ui/src/components/Sidebar/index.tsx b/docs-ui/src/components/Sidebar/index.tsx index 4d86398ef7..6b0db7e4fe 100644 --- a/docs-ui/src/components/Sidebar/index.tsx +++ b/docs-ui/src/components/Sidebar/index.tsx @@ -36,26 +36,12 @@ interface SidebarProps { version: string; } -export const Sidebar = ({ version }: SidebarProps) => { +export const Sidebar = () => { const pathname = usePathname(); const isPlayground = pathname.includes('/playground'); return (
-
- Version {version} - -
diff --git a/docs-ui/src/components/StickyHeader/StickyHeader.module.css b/docs-ui/src/components/StickyHeader/StickyHeader.module.css new file mode 100644 index 0000000000..783b4a55be --- /dev/null +++ b/docs-ui/src/components/StickyHeader/StickyHeader.module.css @@ -0,0 +1,92 @@ +.stickyHeader { + position: fixed; + top: 0px; + left: 32px; + right: 32px; + z-index: 99999; + background-color: var(--background); + padding: 16px 20px 16px 40px; + display: flex; + justify-content: space-between; + align-items: center; + backdrop-filter: blur(10px); + pointer-events: auto; + isolation: isolate; + transform: translateZ(0); + opacity: 0; + width: calc(100% - 64px); + mask-image: linear-gradient(to bottom, black 0%, black 80%, transparent 100%); + -webkit-mask-image: linear-gradient( + to bottom, + black 0%, + black 80%, + transparent 100% + ); +} + +@media (max-width: 768px) { + .stickyHeader { + display: none; + } +} + +.right { + display: flex; + align-items: center; + gap: 24px; +} + +.name { + font-size: 24px; + color: var(--text-primary); + font-weight: 400; +} + +.version { + font-size: 14px; + color: var(--text-secondary); + font-weight: 500; +} + +.actions { + display: flex; + align-items: center; + gap: 16px; +} + +.versionLinks { + display: flex; + align-items: center; + gap: 12px; +} + +.versionLinks a { + color: var(--text-secondary); + transition: color 0.2s ease; +} + +.versionLinks a:hover { + color: var(--text-primary); +} + +@media (max-width: 768px) { + .stickyHeader { + padding: 12px 16px; + } + + .right { + gap: 16px; + } + + .version { + font-size: 12px; + } +} + +@media (min-width: 768px) { + .stickyHeader { + width: calc(100% - 332px - 40px); + left: 332px; + right: 40px; + } +} diff --git a/docs-ui/src/components/StickyHeader/StickyHeader.tsx b/docs-ui/src/components/StickyHeader/StickyHeader.tsx new file mode 100644 index 0000000000..804d759715 --- /dev/null +++ b/docs-ui/src/components/StickyHeader/StickyHeader.tsx @@ -0,0 +1,50 @@ +'use client'; + +import { motion, useScroll, useTransform, circOut } from 'framer-motion'; +import { RiGithubLine, RiNpmjsLine } from '@remixicon/react'; +import { ThemeSelector } from '../Toolbar/theme'; +import { ThemeNameSelector } from '../Toolbar/theme-name'; +import { useCurrentPage } from '@/hooks/useCurrentPage'; +import styles from './StickyHeader.module.css'; + +export const StickyHeader = () => { + const { scrollY } = useScroll(); + const currentPage = useCurrentPage(); + + // Transform scroll position to opacity only + const opacity = useTransform(scrollY, [100, 200], [0, 1], { + clamp: false, + }); + + const yPos = useTransform(scrollY, [200, 500], [-60, 0], { + clamp: true, + ease: circOut, + }); + + return ( + +
{currentPage || 'Backstage UI'}
+
+ + + +
+
+ ); +}; diff --git a/docs-ui/src/components/Toolbar/Logo.tsx b/docs-ui/src/components/Toolbar/Logo.tsx new file mode 100644 index 0000000000..159244ecc7 --- /dev/null +++ b/docs-ui/src/components/Toolbar/Logo.tsx @@ -0,0 +1,20 @@ +export const Logo = () => { + return ( + + + + + ); +}; diff --git a/docs-ui/src/components/Toolbar/Toolbar.module.css b/docs-ui/src/components/Toolbar/Toolbar.module.css index 8142c5464e..5e3fe70808 100644 --- a/docs-ui/src/components/Toolbar/Toolbar.module.css +++ b/docs-ui/src/components/Toolbar/Toolbar.module.css @@ -11,30 +11,50 @@ padding-left: 0.25rem; } -@media (min-width: 960px) { - .toolbar { - left: 332px; - right: 40px; - } -} - .left { + /* width: 296px; */ display: flex; align-items: center; gap: 0.5rem; + padding-right: 20px; } -.name { - margin-top: 3px; - font-size: 28px; - color: #26c9ad; - font-weight: 500; +.right { + flex: 1; + display: flex; + align-items: center; + justify-content: flex-end; } .actions { display: none; } +.version { + display: none; +} + +.versionLinks { + display: flex; + align-items: center; + + 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; + + &:hover { + color: var(--primary); + background-color: var(--action); + } + } +} + @media (min-width: 600px) { .actions { display: flex; @@ -42,3 +62,34 @@ gap: 1rem; } } + +@media (min-width: 768px) { + .toolbar { + right: 40px; + } +} + +@media (min-width: 820px) { + .right { + justify-content: space-between; + } + + .version { + display: flex; + align-items: center; + justify-content: center; + background-color: var(--action); + border-radius: 48px; + padding-inline: 20px; + color: var(--primary); + font-size: 0.875rem; + font-weight: 500; + height: 48px; + } +} + +@media (min-width: 960px) { + .left { + width: 296px; + } +} diff --git a/docs-ui/src/components/Toolbar/Toolbar.tsx b/docs-ui/src/components/Toolbar/Toolbar.tsx index 952b48f5ac..29570739f8 100644 --- a/docs-ui/src/components/Toolbar/Toolbar.tsx +++ b/docs-ui/src/components/Toolbar/Toolbar.tsx @@ -1,31 +1,52 @@ 'use client'; +import { RiGithubLine, RiNpmjsLine } from '@remixicon/react'; +import { motion, useScroll, useTransform } from 'framer-motion'; +import { useRef } from 'react'; +import { Logo } from './Logo'; import { ThemeSelector } from './theme'; import { ThemeNameSelector } from './theme-name'; import styles from './Toolbar.module.css'; -export const Toolbar = () => { +interface ToolbarProps { + version: string; +} + +export const Toolbar = ({ version }: ToolbarProps) => { + const containerRef = useRef(null); + const { scrollY } = useScroll(); + + // Transform scroll velocity to vertical movement + const y = useTransform(scrollY, [0, 100], [0, -20], { + clamp: false, + }); + return ( -
+
- - - -
UI
-
-
- - +
+ +
Version {version} - Alpha
+
+ + + +
+
); }; diff --git a/docs-ui/src/components/Toolbar/theme-name.module.css b/docs-ui/src/components/Toolbar/theme-name.module.css index 58471b8fd7..1e1943b886 100644 --- a/docs-ui/src/components/Toolbar/theme-name.module.css +++ b/docs-ui/src/components/Toolbar/theme-name.module.css @@ -25,19 +25,6 @@ } } -.SelectIcon { - display: flex; -} - -.SelectValue { - font-size: 0.875rem; - font-weight: 400; -} - -.Positioner { - z-index: 20; -} - .Popup { box-sizing: border-box; padding-block: 0.25rem; @@ -73,65 +60,51 @@ } } -.Item { - box-sizing: border-box; - outline: 0; - font-size: 0.875rem; - line-height: 1rem; - padding-block: 0.5rem; - padding-left: 0.625rem; - padding-right: 1rem; - font-size: 0.875rem; - font-weight: 600; - display: grid; - gap: 0.5rem; - align-items: center; - grid-template-columns: 0.75rem 1fr; - cursor: default; - user-select: none; - border-radius: 0.25rem; - cursor: pointer; - transition: background-color 0.2s ease-in-out; +.Popup[data-trigger='Select'] { + min-width: var(--trigger-width); - [data-side='none'] & { - font-size: 1rem; - padding-right: 3rem; - min-width: calc(var(--anchor-width) + 1rem); + .ListBox { + display: block; + width: unset; + max-height: inherit; + min-height: unset; + border: none; + + .react-aria-Header { + padding-left: 1.571rem; + } } - &[data-highlighted] { - z-index: 0; + .Item { position: relative; - color: var(--color-gray-50); - background-color: var(--bg); - } + padding: 0 0.571rem 0 1.571rem; + height: 2rem; + display: flex; + align-items: center; - &[data-highlighted]::before { - content: ''; - z-index: -1; - position: absolute; - inset-block: 0; - inset-inline: 0.25rem; - border-radius: 0.25rem; - background-color: var(--color-gray-900); + &[data-focus-visible] { + outline: none; + } + + &[data-selected] { + font-weight: 600; + background: unset; + color: var(--text-color); + + &::before { + content: '✓'; + content: '✓' / ''; + alt: ' '; + position: absolute; + left: 4px; + } + } + + &[data-focused], + &[data-pressed] { + background: var(--bg); + color: var(--primary); + cursor: pointer; + } } } - -.ItemIndicator { - grid-column-start: 1; - width: 1rem; - height: 1rem; - display: flex; - align-items: center; -} - -.ItemIndicatorIcon { - display: block; - width: 0.75rem; - height: 0.75rem; -} - -.ItemText { - grid-column-start: 2; - font-size: 14px; -} diff --git a/docs-ui/src/components/Toolbar/theme-name.tsx b/docs-ui/src/components/Toolbar/theme-name.tsx index 3cf0d088ef..544c345f86 100644 --- a/docs-ui/src/components/Toolbar/theme-name.tsx +++ b/docs-ui/src/components/Toolbar/theme-name.tsx @@ -1,6 +1,13 @@ 'use client'; -import { Select } from '@base-ui-components/react/select'; +import { + Button, + ListBox, + ListBoxItem, + Popover, + Select, + SelectValue, +} from 'react-aria-components'; import styles from './theme-name.module.css'; import { Icon } from '@backstage/ui'; import { usePlayground } from '@/utils/playground-context'; @@ -15,35 +22,23 @@ export const ThemeNameSelector = () => { const { selectedThemeName, setSelectedThemeName } = usePlayground(); return ( - - - - - - - - - - - {themes.map(({ name, value }) => ( - - - - - - {name} - - - ))} - - - - + + + + {themes.map(({ name, value }) => ( + + {name} + + ))} + + + ); }; diff --git a/docs-ui/src/css/globals.css b/docs-ui/src/css/globals.css index 334e6a870a..9193f49b5a 100644 --- a/docs-ui/src/css/globals.css +++ b/docs-ui/src/css/globals.css @@ -1,5 +1,5 @@ :root { - --bg: #f8f8f8; + --bg: #f4f4f4; --panel: #fff; --primary: #000; --secondary: #929292; diff --git a/docs-ui/src/hooks/useCurrentPage.ts b/docs-ui/src/hooks/useCurrentPage.ts new file mode 100644 index 0000000000..1f5f978846 --- /dev/null +++ b/docs-ui/src/hooks/useCurrentPage.ts @@ -0,0 +1,31 @@ +'use client'; + +import { usePathname } from 'next/navigation'; +import { getPageName } from '@/utils/getPageName'; + +export function useCurrentPage(): string | null { + const pathname = usePathname(); + + // Handle root path + if (pathname === '/') { + return 'Getting Started'; + } + + // Extract slug from various path patterns + const patterns = [ + /^\/components\/(.+)$/, // /components/button + /^\/theme\/(.+)$/, // /theme/typography + /^\/about$/, // /about + /^\/changelog$/, // /changelog + ]; + + for (const pattern of patterns) { + const match = pathname.match(pattern); + if (match) { + const slug = match[1] || pathname.slice(1); // Use full path for exact matches + return getPageName(slug); + } + } + + return null; +} diff --git a/docs-ui/src/utils/getPageName.ts b/docs-ui/src/utils/getPageName.ts new file mode 100644 index 0000000000..9fba42fbb4 --- /dev/null +++ b/docs-ui/src/utils/getPageName.ts @@ -0,0 +1,29 @@ +import { overview, theme, components, layoutComponents } from './data'; + +export function getPageName(slug: string): string | null { + // Search in overview pages + const overviewPage = overview.find(p => p.slug === slug); + if (overviewPage) { + return overviewPage.title; + } + + // Search in theme pages + const themePage = theme.find(p => p.slug === slug); + if (themePage) { + return themePage.title; + } + + // Search in components array + const component = components.find(c => c.slug === slug); + if (component) { + return component.title; + } + + // Search in layoutComponents array + const layoutComponent = layoutComponents.find(c => c.slug === slug); + if (layoutComponent) { + return layoutComponent.title; + } + + return null; +} From aa3133bb3b0c4c2cf7aabc0261f5cd5e5318d289 Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Tue, 22 Jul 2025 20:57:20 +0100 Subject: [PATCH 2/7] Improve Header component Signed-off-by: Charles de Dreuille --- .../src/components/PropsTable/PropsTable.tsx | 18 +- .../PropsTable/TypePopup.module.css | 79 ++++++ .../src/components/PropsTable/TypePopup.tsx | 49 ++++ docs-ui/src/content/components/header.mdx | 69 +++++ .../src/content/components/header.props.ts | 147 ++++++++++ docs-ui/src/content/components/tabs.mdx | 58 ++-- docs-ui/src/content/components/tabs.props.ts | 147 ++++++---- docs-ui/src/snippets/stories-snippets.tsx | 250 +++--------------- docs-ui/src/utils/data.ts | 5 + docs-ui/src/utils/propDefs.ts | 22 +- .../src/components/Header/Header.stories.tsx | 18 +- .../ui/src/components/Tabs/Tabs.stories.tsx | 12 +- 12 files changed, 575 insertions(+), 299 deletions(-) create mode 100644 docs-ui/src/components/PropsTable/TypePopup.module.css create mode 100644 docs-ui/src/components/PropsTable/TypePopup.tsx create mode 100644 docs-ui/src/content/components/header.mdx create mode 100644 docs-ui/src/content/components/header.props.ts diff --git a/docs-ui/src/components/PropsTable/PropsTable.tsx b/docs-ui/src/components/PropsTable/PropsTable.tsx index 8fedeb7c0c..bd54b1e245 100644 --- a/docs-ui/src/components/PropsTable/PropsTable.tsx +++ b/docs-ui/src/components/PropsTable/PropsTable.tsx @@ -2,15 +2,13 @@ import * as Table from '../Table'; import { Chip } from '../Chip'; +import { TypePopup } from './TypePopup'; import { icons } from '../../../../packages/ui'; -// Define a more specific type for the data object -type PropData = { - values?: string | string[]; - responsive?: boolean; - default?: string; - type?: string; -}; +import { PropDef } from '@/utils/propDefs'; + +// Use the proper PropDef type +type PropData = PropDef; // Modify the PropsTable component to use the new type export const PropsTable = >({ @@ -59,6 +57,12 @@ export const PropsTable = >({ string )} + {data[n].type === 'complex' && data[n].complexType && ( + + )} {data[n].type === 'enum | string' && ( <> {enumValues} diff --git a/docs-ui/src/components/PropsTable/TypePopup.module.css b/docs-ui/src/components/PropsTable/TypePopup.module.css new file mode 100644 index 0000000000..294df0b645 --- /dev/null +++ b/docs-ui/src/components/PropsTable/TypePopup.module.css @@ -0,0 +1,79 @@ +.button { + display: inline-flex; + align-items: center; + font-family: monospace; + font-size: 13px; + border-radius: 6px; + padding: 0px 8px; + height: 24px; + margin-right: 4px; + background-color: #f0f0f0; + color: #5d5d5d; + cursor: pointer; + border: none; + outline: none; + box-shadow: none; + text-decoration: underline; +} + +[data-theme='dark'] .button { + background-color: #2c2c2c; + color: #fff; +} + +.popover { + border: 1px solid var(--border); + box-shadow: 0 8px 20px rgba(0 0 0 / 0.1); + border-radius: 6px; + background: var(--panel); + color: var(--primary); + outline: none; + /* max-width: 400px; */ + transition: transform 200ms, opacity 200ms; + padding: 1rem; + margin-top: 6px; + --origin: translateY(-8px); + + &[data-entering], + &[data-exiting] { + transform: var(--origin); + opacity: 0; + } +} + +.arrow svg { + display: block; + fill: var(--panel); + stroke: var(--border); + stroke-width: 1px; + transform: rotate(180deg); +} + +.name { + font-size: 14px; + font-weight: 500; + margin-bottom: 1rem; +} + +.grid { + display: grid; + grid-template-columns: auto auto 1fr; + gap: 0.5rem 1rem; +} + +.col1 { + font-size: 13px; + font-weight: 500; + color: var(--text-secondary); + padding-top: 0.25rem; +} + +.col2 { + font-size: 13px; +} + +.col3 { + font-size: 13px; + color: var(--text-secondary); + padding-top: 0.25rem; +} diff --git a/docs-ui/src/components/PropsTable/TypePopup.tsx b/docs-ui/src/components/PropsTable/TypePopup.tsx new file mode 100644 index 0000000000..bd0fc5dd76 --- /dev/null +++ b/docs-ui/src/components/PropsTable/TypePopup.tsx @@ -0,0 +1,49 @@ +import { ComplexTypeDef } from '@/utils/propDefs'; +import { Chip } from '../Chip'; +import { + Button, + Dialog, + DialogTrigger, + OverlayArrow, + Popover, +} from 'react-aria-components'; +import styles from './TypePopup.module.css'; + +interface TypePopupProps { + complexType: ComplexTypeDef; + name: string; +} + +export const TypePopup = ({ complexType, name }: TypePopupProps) => { + return ( + + + + + + + + + +
{complexType.name}
+
+ {Object.entries(complexType.properties).map( + ([propName, propDef]) => [ +
+ {propName} + {propDef.required ? '' : '?'} +
, +
+ {propDef.type} +
, +
+ {propDef.description} +
, + ], + )} +
+
+
+
+ ); +}; diff --git a/docs-ui/src/content/components/header.mdx b/docs-ui/src/content/components/header.mdx new file mode 100644 index 0000000000..d59dd79613 --- /dev/null +++ b/docs-ui/src/content/components/header.mdx @@ -0,0 +1,69 @@ +import { PropsTable } from '@/components/PropsTable'; +import { CodeBlock } from '@/components/CodeBlock'; +import { Snippet } from '@/components/Snippet'; +import { HeaderSnippet } from '@/snippets/stories-snippets'; +import { + propDefs, + flexUsageSnippet, + flexDefaultSnippet, + flexFAQ1Snippet, + flexSimpleSnippet, + flexResponsiveSnippet, + flexAlignSnippet, + usage, + defaultSnippet, +} from './header.props'; +import { spacingPropDefs } from '@/utils/propDefs'; +import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; + + + +} + code={defaultSnippet} +/> + +## Usage + + + +## API reference + + + +The grid component also accepts all the spacing props from the Box component. + + + +## Examples + +### Simple + +A simple example of how to use the Flex component. + + + +### Responsive + +The Flex component also supports responsive values, making it easy to create +responsive designs. + + + +### Align + +The Flex component also supports responsive alignment, making it easy to +create responsive designs. + + + + + + diff --git a/docs-ui/src/content/components/header.props.ts b/docs-ui/src/content/components/header.props.ts new file mode 100644 index 0000000000..ee22fb7d67 --- /dev/null +++ b/docs-ui/src/content/components/header.props.ts @@ -0,0 +1,147 @@ +import { + childrenPropDefs, + classNamePropDefs, + stylePropDefs, + type PropDef, +} from '@/utils/propDefs'; + +export const propDefs: Record = { + icon: { + type: 'enum', + values: ['ReactNode'], + }, + title: { + type: 'string', + default: 'Your plugin', + }, + titleLink: { + type: 'string', + default: '/', + }, + breadcrumbs: { + type: 'complex', + complexType: { + name: 'Breadcrumb[]', + properties: { + label: { + type: 'string', + required: true, + description: 'Display text for the breadcrumb', + }, + href: { + type: 'string', + required: true, + description: 'URL for the breadcrumb link', + }, + }, + }, + }, + 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 { Header } from '@backstage/ui'; + +
`; + +export const defaultSnippet = `
+ } /> + } /> + } /> + + } +/>`; + +export const flexSimpleSnippet = ` + Hello World + Hello World + Hello World +`; + +export const flexResponsiveSnippet = ` + Hello World + Hello World + Hello World +`; + +export const flexAlignSnippet = ` + Hello World + Hello World + Hello World +`; diff --git a/docs-ui/src/content/components/tabs.mdx b/docs-ui/src/content/components/tabs.mdx index dd0552b436..26905d4733 100644 --- a/docs-ui/src/content/components/tabs.mdx +++ b/docs-ui/src/content/components/tabs.mdx @@ -3,12 +3,13 @@ import { TabsSnippet } from '@/snippets/stories-snippets'; import { Snippet } from '@/components/Snippet'; import { CodeBlock } from '@/components/CodeBlock'; import { - tabsRootPropDefs, - tabsListPropDefs, - tabsTabPropDefs, - tabsPanelPropDefs, + tabsPropDefs, + tabPropDefs, tabsUsageSnippet, tabsDefaultSnippet, + tabsWithTabPanelsSnippet, + tabsWithLinksSnippet, + tabsWithDeeplyNestedRoutesSnippet, } from './tabs.props'; import { PageTitle } from '@/components/PageTitle'; import { Theming } from '@/components/Theming'; @@ -31,29 +32,52 @@ import { ChangelogComponent } from '@/components/ChangelogComponent'; ## API reference -### Tabs.Root +### Tabs Groups the tabs and the corresponding panels. Renders a `
` element. - + -### Tabs.List - -Groups the individual tab buttons. Renders a `
` element. - - - -### Tabs.Tab +### Tab An individual interactive tab button that toggles the corresponding panel. Renders a `, menuItems, }, decorators: [withRouter], + render: args => ( +
Custom action} /> + ), }; export const WithBreadcrumbs: Story = { @@ -185,11 +187,25 @@ export const WithBreadcrumbs: Story = { export const WithAllComponents: Story = { args: { + title: 'My plugin', + titleLink: '/', menuItems, tabs, breadcrumbs, }, decorators: [withRouter], + render: args => ( +
+ } /> + } /> + } /> + + } + /> + ), }; export const WithLayout: Story = { diff --git a/packages/ui/src/components/Tabs/Tabs.stories.tsx b/packages/ui/src/components/Tabs/Tabs.stories.tsx index 9f6e05e289..a0a1fa75dc 100644 --- a/packages/ui/src/components/Tabs/Tabs.stories.tsx +++ b/packages/ui/src/components/Tabs/Tabs.stories.tsx @@ -95,10 +95,10 @@ export const WithMockedURLTab2: Story = { - + Current URL is mocked to be: /tab2 - + Notice how the "Tab 2" tab is selected (highlighted) because it matches the current path. @@ -273,14 +273,16 @@ export const PrefixMatchingDeepNesting: Story = { - + Current URL: /catalog/users/john/details - + The "Catalog" tab is active because it uses prefix matching and the URL starts with "/catalog". - This works for any level of nesting under "/catalog". + + This works for any level of nesting under "/catalog". + ), From 96e6e087cdf18be0f2f91d88f00c915d88467901 Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Tue, 22 Jul 2025 21:38:23 +0100 Subject: [PATCH 3/7] Improve Header and HeaderPage content Signed-off-by: Charles de Dreuille --- .../StickyHeader/StickyHeader.module.css | 22 ++-- .../src/components/Toolbar/Toolbar.module.css | 3 +- .../src/content/components/header-page.mdx | 40 +++++++ .../content/components/header-page.props.ts | 91 ++++++++++++++++ docs-ui/src/content/components/header.mdx | 62 +++++++---- .../src/content/components/header.props.ts | 101 +++++++++++++++--- docs-ui/src/css/globals.css | 2 + docs-ui/src/utils/data.ts | 5 + .../src/components/Header/Header.stories.tsx | 79 +++++++++----- 9 files changed, 334 insertions(+), 71 deletions(-) create mode 100644 docs-ui/src/content/components/header-page.mdx create mode 100644 docs-ui/src/content/components/header-page.props.ts 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, From 5519be9762b26b7ad727452f2260de28e26e6aed Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Tue, 22 Jul 2025 21:45:51 +0100 Subject: [PATCH 4/7] Fixes types Signed-off-by: Charles de Dreuille --- docs-ui/src/app/theme/typography/page.mdx | 22 +--------------------- docs-ui/src/components/Sidebar/index.tsx | 5 ----- docs-ui/src/snippets/stories-snippets.tsx | 2 ++ 3 files changed, 3 insertions(+), 26 deletions(-) diff --git a/docs-ui/src/app/theme/typography/page.mdx b/docs-ui/src/app/theme/typography/page.mdx index 31c55b8e25..e8891c34f8 100644 --- a/docs-ui/src/app/theme/typography/page.mdx +++ b/docs-ui/src/app/theme/typography/page.mdx @@ -1,4 +1,4 @@ -import { HeadingSnippet, TextSnippet } from '@/snippets/stories-snippets'; +import { TextSnippet } from '@/snippets/stories-snippets'; import { Snippet } from '@/components/Snippet'; # Typography @@ -9,26 +9,6 @@ appearance to match your brand, the underlying API remains consistent and unchanged. Each component is built on a responsive structure, allowing you to define different typography values for various breakpoints. -## Headings - -Headings are used to structure the content of your page. They are used to -create a hierarchy of information and to make the content more readable. The -best way to use add these headings to your page is to import the [Heading -component](?path=/docs/components-heading--docs). - -} - code={` - Display - Title 1 - Title 2 - Title 3 - Title 4 -`} -/> - ## Text Backstage UI provides four distinct text variants, each offering different font sizes diff --git a/docs-ui/src/components/Sidebar/index.tsx b/docs-ui/src/components/Sidebar/index.tsx index 6b0db7e4fe..02308001d6 100644 --- a/docs-ui/src/components/Sidebar/index.tsx +++ b/docs-ui/src/components/Sidebar/index.tsx @@ -7,7 +7,6 @@ import Link from 'next/link'; import { usePathname } from 'next/navigation'; import { motion } from 'motion/react'; import { Fragment } from 'react'; -import { RiGithubLine, RiNpmjsLine } from '@remixicon/react'; const data = [ { @@ -32,10 +31,6 @@ const data = [ }, ]; -interface SidebarProps { - version: string; -} - export const Sidebar = () => { const pathname = usePathname(); const isPlayground = pathname.includes('/playground'); diff --git a/docs-ui/src/snippets/stories-snippets.tsx b/docs-ui/src/snippets/stories-snippets.tsx index 29cda0268f..92d4362d98 100644 --- a/docs-ui/src/snippets/stories-snippets.tsx +++ b/docs-ui/src/snippets/stories-snippets.tsx @@ -28,11 +28,13 @@ import * as HeaderStories from '../../../packages/ui/src/components/Header/Heade import * as HeaderPageStories from '../../../packages/ui/src/components/HeaderPage/HeaderPage.stories'; // Helper function to create snippet components +// eslint-disable-next-line @typescript-eslint/no-explicit-any const createSnippetComponent = (stories: any) => { return function SnippetComponent({ story }: { story: string }) { const composedStories = composeStories(stories); const StoryComponent = composedStories[ story as keyof typeof composedStories + // eslint-disable-next-line @typescript-eslint/no-explicit-any ] as any; return StoryComponent ? : null; From b829a7427bf6a716e22f112f9b17c56cba685615 Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Wed, 23 Jul 2025 07:36:21 +0100 Subject: [PATCH 5/7] Fix sidebar links Signed-off-by: Charles de Dreuille --- .../src/app/{theme => }/iconography/page.mdx | 0 docs-ui/src/app/{theme => }/layout/page.mdx | 0 .../src/app/{theme => }/responsive/page.mdx | 0 docs-ui/src/app/theme/typography/page.mdx | 45 ------------------- docs-ui/src/app/{theme => }/theming/page.mdx | 0 docs-ui/src/components/Sidebar/index.tsx | 13 ++++-- docs-ui/src/utils/data.ts | 6 +-- docs-ui/src/utils/getPageName.ts | 10 ++--- 8 files changed, 15 insertions(+), 59 deletions(-) rename docs-ui/src/app/{theme => }/iconography/page.mdx (100%) rename docs-ui/src/app/{theme => }/layout/page.mdx (100%) rename docs-ui/src/app/{theme => }/responsive/page.mdx (100%) delete mode 100644 docs-ui/src/app/theme/typography/page.mdx rename docs-ui/src/app/{theme => }/theming/page.mdx (100%) diff --git a/docs-ui/src/app/theme/iconography/page.mdx b/docs-ui/src/app/iconography/page.mdx similarity index 100% rename from docs-ui/src/app/theme/iconography/page.mdx rename to docs-ui/src/app/iconography/page.mdx diff --git a/docs-ui/src/app/theme/layout/page.mdx b/docs-ui/src/app/layout/page.mdx similarity index 100% rename from docs-ui/src/app/theme/layout/page.mdx rename to docs-ui/src/app/layout/page.mdx diff --git a/docs-ui/src/app/theme/responsive/page.mdx b/docs-ui/src/app/responsive/page.mdx similarity index 100% rename from docs-ui/src/app/theme/responsive/page.mdx rename to docs-ui/src/app/responsive/page.mdx diff --git a/docs-ui/src/app/theme/typography/page.mdx b/docs-ui/src/app/theme/typography/page.mdx deleted file mode 100644 index e8891c34f8..0000000000 --- a/docs-ui/src/app/theme/typography/page.mdx +++ /dev/null @@ -1,45 +0,0 @@ -import { TextSnippet } from '@/snippets/stories-snippets'; -import { Snippet } from '@/components/Snippet'; - -# Typography - -Backstage UI offers a suite of typography components designed to seamlessly align -with the rest of your Backstage instance. While you can customize their -appearance to match your brand, the underlying API remains consistent and -unchanged. Each component is built on a responsive structure, allowing you to -define different typography values for various breakpoints. - -## Text - -Backstage UI provides four distinct text variants, each offering different font sizes -carefully designed to cover the majority of use cases. These variants are -versatile and can be paired with regular and bold of font weights. You can use -the [Text component](?path=/docs/components-text--docs) to add text to your -page. - -} - code={` - - A man looks at a painting in a museum and says, “Brothers and sisters I - have none, but that man's father is my father's son.” Who is - in the painting? - - - A man looks at a painting in a museum and says, “Brothers and sisters I - have none, but that man's father is my father's son.” Who is - in the painting? - - - A man looks at a painting in a museum and says, “Brothers and sisters I - have none, but that man's father is my father's son.” Who is - in the painting? - - - A man looks at a painting in a museum and says, “Brothers and sisters I - have none, but that man's father is my father's son.” Who is - in the painting? - - `} -/> diff --git a/docs-ui/src/app/theme/theming/page.mdx b/docs-ui/src/app/theming/page.mdx similarity index 100% rename from docs-ui/src/app/theme/theming/page.mdx rename to docs-ui/src/app/theming/page.mdx diff --git a/docs-ui/src/components/Sidebar/index.tsx b/docs-ui/src/components/Sidebar/index.tsx index 02308001d6..59e297e26e 100644 --- a/docs-ui/src/components/Sidebar/index.tsx +++ b/docs-ui/src/components/Sidebar/index.tsx @@ -1,7 +1,12 @@ 'use client'; import styles from './Sidebar.module.css'; -import { components, overview, layoutComponents, theme } from '@/utils/data'; +import { + components, + overview, + layoutComponents, + coreConcepts, +} from '@/utils/data'; import { ScrollArea } from '@base-ui-components/react/scroll-area'; import Link from 'next/link'; import { usePathname } from 'next/navigation'; @@ -15,9 +20,9 @@ const data = [ url: '', }, { - title: 'Theme', - content: theme, - url: '/theme', + title: 'Core Concepts', + content: coreConcepts, + url: '', }, { title: 'Layout Components', diff --git a/docs-ui/src/utils/data.ts b/docs-ui/src/utils/data.ts index 348f4df24e..9cdeff14f0 100644 --- a/docs-ui/src/utils/data.ts +++ b/docs-ui/src/utils/data.ts @@ -19,7 +19,7 @@ export const overview: Page[] = [ }, ]; -export const theme: Page[] = [ +export const coreConcepts: Page[] = [ { title: 'Iconography', slug: 'iconography', @@ -36,10 +36,6 @@ export const theme: Page[] = [ title: 'Theming', slug: 'theming', }, - { - title: 'Typography', - slug: 'typography', - }, ]; export const layoutComponents: Page[] = [ diff --git a/docs-ui/src/utils/getPageName.ts b/docs-ui/src/utils/getPageName.ts index 9fba42fbb4..a3298bc9b7 100644 --- a/docs-ui/src/utils/getPageName.ts +++ b/docs-ui/src/utils/getPageName.ts @@ -1,4 +1,4 @@ -import { overview, theme, components, layoutComponents } from './data'; +import { overview, coreConcepts, components, layoutComponents } from './data'; export function getPageName(slug: string): string | null { // Search in overview pages @@ -7,10 +7,10 @@ export function getPageName(slug: string): string | null { return overviewPage.title; } - // Search in theme pages - const themePage = theme.find(p => p.slug === slug); - if (themePage) { - return themePage.title; + // Search in core concepts array + const coreConcept = coreConcepts.find(c => c.slug === slug); + if (coreConcept) { + return coreConcept.title; } // Search in components array From 370a9dfae1d7e007ee12fda7ebb8450192c1169f Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Wed, 23 Jul 2025 08:37:28 +0100 Subject: [PATCH 6/7] Fix home Signed-off-by: Charles de Dreuille --- docs-ui/public/css-classname-structure.png | Bin 43849 -> 42743 bytes docs-ui/src/app/install/page.mdx | 36 ++++ docs-ui/src/app/page.mdx | 176 +++++++++++++++--- .../ComponentCards/ComponentCards.module.css | 36 ++++ .../ComponentCards/ComponentCards.tsx | 23 +++ .../src/components/ComponentCards/index.ts | 1 + docs-ui/src/css/globals.css | 2 + docs-ui/src/utils/data.ts | 4 + 8 files changed, 255 insertions(+), 23 deletions(-) create mode 100644 docs-ui/src/app/install/page.mdx create mode 100644 docs-ui/src/components/ComponentCards/ComponentCards.module.css create mode 100644 docs-ui/src/components/ComponentCards/ComponentCards.tsx create mode 100644 docs-ui/src/components/ComponentCards/index.ts diff --git a/docs-ui/public/css-classname-structure.png b/docs-ui/public/css-classname-structure.png index df9894ff2b7c511fa9f439a6a7fcde5d4f903732..c241b182cc49d9044901d7e4c0dcbb30479bf006 100644 GIT binary patch literal 42743 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%0A?n$6(Iz|bvJ3c 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 + +## 2. Import the css files + +Import the global CSS file at the root of your application. + +```tsx +import '@backstage/ui/css/styles.css'; +``` + +## 3. Start building ✨ + +Now you can start building your plugin using the new design system. + +```tsx +import { Flex, Button, Text } from '@backstage/ui'; + + + Hello World + +; +``` + +## Next steps + +Now that you have the basics down, you can start building your plugin using the new design system. +Please familiarise yourself first with our theming principles. This will help you understand the core concepts of the design system. +If you have any questions, please reach out to us on [Discord](https://discord.gg/MUpMjP2). diff --git a/docs-ui/src/app/page.mdx b/docs-ui/src/app/page.mdx index 27d7bc66d4..f31cf4524e 100644 --- a/docs-ui/src/app/page.mdx +++ b/docs-ui/src/app/page.mdx @@ -1,43 +1,173 @@ -import { CodeBlock } from '@/components/CodeBlock'; +import { ComponentCards, ComponentCard } from '@/components/ComponentCards'; -# Backstage UI +## Welcome to Backstage UI, the new design library for Backstage plugins. -Welcome to the Backstage UI, the new design library for Backstage plugins. This -project is still under active development but we will make sure to document +This project is still under active development but we will make sure to document the API as we go. We are aiming to improve the general UI of Backstage and plugins across Backstage. This new library will take time to build but we are building it incrementally with not conflict with the existing theming system. -## Installation +### Actions -### 1. Install Backstage UI + + + + + + -Install Backstage UI using a package manager. +### Layout - + + + + + + + + -### 2. Import the css files +### Selection and inputs -Import the global CSS file at the root of your application. + + + + + + + + -```tsx -import '@backstage/ui/css/styles.css'; -``` +### Navigation -### 3. Start building ✨ + + + + + + -Now you can start building your plugin using the new design system. +### Images and icons -```tsx -import { Flex, Button, Text } from '@backstage/ui'; + + + + - - Hello World - -; -``` +### Feedback indicators -## Next steps + + + + + +### Typography + + + + + +## Support Now that you have the basics down, you can start building your plugin using the new design system. Please familiarise yourself first with our theming principles. This will help you understand the core concepts of the design system. diff --git a/docs-ui/src/components/ComponentCards/ComponentCards.module.css b/docs-ui/src/components/ComponentCards/ComponentCards.module.css new file mode 100644 index 0000000000..cf003472b4 --- /dev/null +++ b/docs-ui/src/components/ComponentCards/ComponentCards.module.css @@ -0,0 +1,36 @@ +.grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 1rem; + margin-top: 1rem; + margin-bottom: 3rem; +} + +.card { + display: flex; + flex-direction: column; + justify-content: flex-end; + background-color: var(--panel); + border-radius: 8px; + border: 1px solid var(--border); + padding: 16px; + gap: 4px; + min-height: 120px; + + &:hover { + background-color: var(--panel-hover); + } +} + +.title { + margin: 0; + font-size: 16px; + font-weight: 600; + color: var(--primary); +} + +.description { + margin: 0; + font-size: 14px; + color: var(--secondary); +} diff --git a/docs-ui/src/components/ComponentCards/ComponentCards.tsx b/docs-ui/src/components/ComponentCards/ComponentCards.tsx new file mode 100644 index 0000000000..0e4d22c02a --- /dev/null +++ b/docs-ui/src/components/ComponentCards/ComponentCards.tsx @@ -0,0 +1,23 @@ +import Link from 'next/link'; +import styles from './ComponentCards.module.css'; + +export const ComponentCards = ({ children }: { children: React.ReactNode }) => { + return
{children}
; +}; + +export const ComponentCard = ({ + title, + description, + href, +}: { + title: string; + description: string; + href: string; +}) => { + return ( + +

{title}

+

{description}

+ + ); +}; diff --git a/docs-ui/src/components/ComponentCards/index.ts b/docs-ui/src/components/ComponentCards/index.ts new file mode 100644 index 0000000000..4bc4beaae3 --- /dev/null +++ b/docs-ui/src/components/ComponentCards/index.ts @@ -0,0 +1 @@ +export * from './ComponentCards'; diff --git a/docs-ui/src/css/globals.css b/docs-ui/src/css/globals.css index 69a2c8ddfe..5d8422bd30 100644 --- a/docs-ui/src/css/globals.css +++ b/docs-ui/src/css/globals.css @@ -1,6 +1,7 @@ :root { --bg: #f4f4f4; --panel: #fff; + --panel-hover: #fafafa; --primary: #000; --secondary: #929292; --action: #fff; @@ -20,6 +21,7 @@ [data-theme='dark'] { --bg: #000; --panel: #181818; + --panel-hover: #202020; --primary: #fff; --secondary: #818181; --action: #202020; diff --git a/docs-ui/src/utils/data.ts b/docs-ui/src/utils/data.ts index 9cdeff14f0..752f28c2c5 100644 --- a/docs-ui/src/utils/data.ts +++ b/docs-ui/src/utils/data.ts @@ -9,6 +9,10 @@ export const overview: Page[] = [ title: 'Getting Started', slug: '', }, + { + title: 'Installation', + slug: 'install', + }, { title: 'About', slug: 'about', From ad5beb434572df8987ef9b83bc88f27f5ba47dec Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Wed, 23 Jul 2025 08:47:39 +0100 Subject: [PATCH 7/7] Update ComponentCards.module.css Signed-off-by: Charles de Dreuille --- .../ComponentCards/ComponentCards.module.css | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/docs-ui/src/components/ComponentCards/ComponentCards.module.css b/docs-ui/src/components/ComponentCards/ComponentCards.module.css index cf003472b4..688010110c 100644 --- a/docs-ui/src/components/ComponentCards/ComponentCards.module.css +++ b/docs-ui/src/components/ComponentCards/ComponentCards.module.css @@ -1,11 +1,29 @@ .grid { display: grid; - grid-template-columns: repeat(4, 1fr); + grid-template-columns: repeat(1, 1fr); gap: 1rem; margin-top: 1rem; margin-bottom: 3rem; } +@media (min-width: 768px) { + .grid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (min-width: 1024px) { + .grid { + grid-template-columns: repeat(3, 1fr); + } +} + +@media (min-width: 1280px) { + .grid { + grid-template-columns: repeat(4, 1fr); + } +} + .card { display: flex; flex-direction: column;