From 87f1a39581918b4be256046502625d00de7545cf Mon Sep 17 00:00:00 2001 From: David Orozco <34346877+davixcky@users.noreply.github.com> Date: Wed, 9 Jul 2025 11:55:33 -0500 Subject: [PATCH 01/16] Add signadot.yaml Signed-off-by: David Orozco <34346877+davixcky@users.noreply.github.com> --- microsite/data/plugins/signadot.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 microsite/data/plugins/signadot.yaml diff --git a/microsite/data/plugins/signadot.yaml b/microsite/data/plugins/signadot.yaml new file mode 100644 index 0000000000..cb0f10f168 --- /dev/null +++ b/microsite/data/plugins/signadot.yaml @@ -0,0 +1,10 @@ +--- +title: Signadot +author: signadot +authorUrl: https://www.signadot.com/ +category: CI +description: Create and manage Signadot resources like Sandboxes, Clusters, etc +documentation: https://github.com/signadot/backstage-plugin +iconUrl: https://avatars.githubusercontent.com/u/57196635 +npmPackageName: @signadot-lib/backstage-plugin +addedDate: '2025-07-09' From 95a668831379e019c078b2df68df0b9c0d0a73bf Mon Sep 17 00:00:00 2001 From: David Orozco <34346877+davixcky@users.noreply.github.com> Date: Wed, 9 Jul 2025 14:51:22 -0500 Subject: [PATCH 02/16] Update signadot.yaml Signed-off-by: David Orozco <34346877+davixcky@users.noreply.github.com> --- microsite/data/plugins/signadot.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/microsite/data/plugins/signadot.yaml b/microsite/data/plugins/signadot.yaml index cb0f10f168..359fe89276 100644 --- a/microsite/data/plugins/signadot.yaml +++ b/microsite/data/plugins/signadot.yaml @@ -6,5 +6,5 @@ category: CI description: Create and manage Signadot resources like Sandboxes, Clusters, etc documentation: https://github.com/signadot/backstage-plugin iconUrl: https://avatars.githubusercontent.com/u/57196635 -npmPackageName: @signadot-lib/backstage-plugin +npmPackageName: '@signadot-lib/backstage-plugin' addedDate: '2025-07-09' From 31e11548c503154906e5c865b3b9a378c8e3fb4b Mon Sep 17 00:00:00 2001 From: David Orozco Date: Mon, 14 Jul 2025 11:48:48 -0500 Subject: [PATCH 03/16] apply prettier Signed-off-by: David Orozco --- microsite/data/plugins/signadot.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/microsite/data/plugins/signadot.yaml b/microsite/data/plugins/signadot.yaml index 359fe89276..183e9a3056 100644 --- a/microsite/data/plugins/signadot.yaml +++ b/microsite/data/plugins/signadot.yaml @@ -2,9 +2,9 @@ title: Signadot author: signadot authorUrl: https://www.signadot.com/ -category: CI +category: CI description: Create and manage Signadot resources like Sandboxes, Clusters, etc documentation: https://github.com/signadot/backstage-plugin iconUrl: https://avatars.githubusercontent.com/u/57196635 npmPackageName: '@signadot-lib/backstage-plugin' -addedDate: '2025-07-09' +addedDate: '2025-07-09' From 06d84bad5daaaa0e76c1edcc88ebd3b2483d2282 Mon Sep 17 00:00:00 2001 From: David Orozco Date: Mon, 14 Jul 2025 14:15:26 -0500 Subject: [PATCH 04/16] update description and author Signed-off-by: David Orozco --- microsite/data/plugins/signadot.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/microsite/data/plugins/signadot.yaml b/microsite/data/plugins/signadot.yaml index 183e9a3056..9b6b162901 100644 --- a/microsite/data/plugins/signadot.yaml +++ b/microsite/data/plugins/signadot.yaml @@ -1,9 +1,9 @@ --- title: Signadot -author: signadot +author: Signadot authorUrl: https://www.signadot.com/ -category: CI -description: Create and manage Signadot resources like Sandboxes, Clusters, etc +category: Kubernetes +description: View and manage lightweight ephemeral Kubernetes environments (Sandboxes) for testing microservices in pull requests and local development. documentation: https://github.com/signadot/backstage-plugin iconUrl: https://avatars.githubusercontent.com/u/57196635 npmPackageName: '@signadot-lib/backstage-plugin' From e0e886fca98bdf5706b4f1914561e64d35ad111c Mon Sep 17 00:00:00 2001 From: Jonathan Roebuck Date: Fri, 18 Jul 2025 13:15:03 +0100 Subject: [PATCH 05/16] add header tab change event Signed-off-by: Jonathan Roebuck --- .changeset/twenty-pumas-brush.md | 5 +++++ packages/ui/report.api.md | 4 +++- packages/ui/src/components/Header/Header.tsx | 2 +- packages/ui/src/components/Header/types.ts | 3 +++ 4 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 .changeset/twenty-pumas-brush.md diff --git a/.changeset/twenty-pumas-brush.md b/.changeset/twenty-pumas-brush.md new file mode 100644 index 0000000000..6306fe0607 --- /dev/null +++ b/.changeset/twenty-pumas-brush.md @@ -0,0 +1,5 @@ +--- +'@backstage/ui': patch +--- + +Adds onTabSelectionChange to ui header component. diff --git a/packages/ui/report.api.md b/packages/ui/report.api.md index 7ef69560d1..6f6fc41fdb 100644 --- a/packages/ui/report.api.md +++ b/packages/ui/report.api.md @@ -29,7 +29,7 @@ import { Table as Table_2 } from '@tanstack/react-table'; import type { TabListProps as TabListProps_2 } from 'react-aria-components'; import type { TabPanelProps as TabPanelProps_2 } from 'react-aria-components'; import { TabProps } from 'react-aria-components'; -import type { TabsProps as TabsProps_2 } from 'react-aria-components'; +import { TabsProps as TabsProps_2 } from 'react-aria-components'; import { TdHTMLAttributes } from 'react'; import type { TextFieldProps as TextFieldProps_2 } from 'react-aria-components'; import { ThHTMLAttributes } from 'react'; @@ -1040,6 +1040,8 @@ export interface HeaderProps { // (undocumented) menuItems?: HeaderMenuItem[]; // (undocumented) + onTabSelectionChange?: TabsProps_2['onSelectionChange']; + // (undocumented) tabs?: HeaderTab[]; // (undocumented) title?: string; diff --git a/packages/ui/src/components/Header/Header.tsx b/packages/ui/src/components/Header/Header.tsx index e6aae08eeb..4f85d9096d 100644 --- a/packages/ui/src/components/Header/Header.tsx +++ b/packages/ui/src/components/Header/Header.tsx @@ -50,7 +50,7 @@ export const Header = (props: HeaderProps) => { /> {tabs && (
- + {tabs?.map(tab => ( diff --git a/packages/ui/src/components/Header/types.ts b/packages/ui/src/components/Header/types.ts index e1156c9a55..cf76929389 100644 --- a/packages/ui/src/components/Header/types.ts +++ b/packages/ui/src/components/Header/types.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { TabsProps } from 'react-aria-components'; + /** * Props for the main Header component. * @@ -26,6 +28,7 @@ export interface HeaderProps { customActions?: React.ReactNode; menuItems?: HeaderMenuItem[]; tabs?: HeaderTab[]; + onTabSelectionChange?: TabsProps['onSelectionChange']; } /** From eb479117f1d1117d42138f97036e211713eafae7 Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Sun, 20 Jul 2025 08:43:14 +0100 Subject: [PATCH 06/16] Updating docs-ui layout Signed-off-by: Charles de Dreuille --- docs-ui/src/app/(docs)/layout.module.css | 1 - docs-ui/src/app/layout.module.css | 21 +++ docs-ui/src/app/layout.tsx | 14 +- .../src/components/Sidebar/Sidebar.module.css | 86 +++++------- docs-ui/src/components/Sidebar/docs.tsx | 82 ------------ docs-ui/src/components/Sidebar/index.tsx | 123 +++++++++++------- docs-ui/src/components/Sidebar/playground.tsx | 77 ----------- .../src/components/Toolbar/Toolbar.module.css | 31 +++++ docs-ui/src/components/Toolbar/Toolbar.tsx | 30 +++++ docs-ui/src/components/Toolbar/index.ts | 1 + docs-ui/src/components/Toolbar/index.tsx | 18 --- .../src/components/Toolbar/styles.module.css | 22 ---- docs-ui/src/css/globals.css | 2 - docs-ui/src/css/page.module.css | 50 ------- 14 files changed, 203 insertions(+), 355 deletions(-) create mode 100644 docs-ui/src/app/layout.module.css delete mode 100644 docs-ui/src/components/Sidebar/docs.tsx delete mode 100644 docs-ui/src/components/Sidebar/playground.tsx create mode 100644 docs-ui/src/components/Toolbar/Toolbar.module.css create mode 100644 docs-ui/src/components/Toolbar/Toolbar.tsx create mode 100644 docs-ui/src/components/Toolbar/index.ts delete mode 100644 docs-ui/src/components/Toolbar/index.tsx delete mode 100644 docs-ui/src/components/Toolbar/styles.module.css delete mode 100644 docs-ui/src/css/page.module.css diff --git a/docs-ui/src/app/(docs)/layout.module.css b/docs-ui/src/app/(docs)/layout.module.css index fa94ef3a13..a4ea17aaac 100644 --- a/docs-ui/src/app/(docs)/layout.module.css +++ b/docs-ui/src/app/(docs)/layout.module.css @@ -2,5 +2,4 @@ width: 100%; max-width: 960px; margin: 0 auto; - padding: 0 24px 64px; } diff --git a/docs-ui/src/app/layout.module.css b/docs-ui/src/app/layout.module.css new file mode 100644 index 0000000000..895067c300 --- /dev/null +++ b/docs-ui/src/app/layout.module.css @@ -0,0 +1,21 @@ +.container { + position: relative; + z-index: 20; + width: 100%; + margin-inline: 0 16px; + margin-top: 112px; + margin-bottom: 48px; + padding-inline: 40px; + padding-block: 48px; + background-color: white; + width: calc(100% - 32px); + border-radius: 0.5rem; +} + +@media (min-width: 768px) { + .container { + width: calc(100% - 332px - 40px); + margin-left: 332px; + margin-right: 40px; + } +} diff --git a/docs-ui/src/app/layout.tsx b/docs-ui/src/app/layout.tsx index 092bca57d4..7ee30ddfa0 100644 --- a/docs-ui/src/app/layout.tsx +++ b/docs-ui/src/app/layout.tsx @@ -3,7 +3,7 @@ import { Sidebar } from '../components/Sidebar'; import { Toolbar } from '@/components/Toolbar'; import { Providers } from './providers'; import { CustomTheme } from '@/components/CustomTheme'; -import styles from '../css/page.module.css'; +import styles from './layout.module.css'; import '../css/globals.css'; import '/public/theme-backstage.css'; @@ -29,14 +29,10 @@ export default function RootLayout({ > -
- -
- - {children} -
- -
+ + +
{children}
+
diff --git a/docs-ui/src/components/Sidebar/Sidebar.module.css b/docs-ui/src/components/Sidebar/Sidebar.module.css index 7d2a13a3f3..4fad36c74d 100644 --- a/docs-ui/src/components/Sidebar/Sidebar.module.css +++ b/docs-ui/src/components/Sidebar/Sidebar.module.css @@ -6,15 +6,11 @@ .sidebar { display: block; position: fixed; - top: 16px; - left: 16px; - border-radius: 8px; - width: 300px; - height: calc(100vh - 32px); - box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.025); + top: 112px; + left: 0; + width: 332px; + height: calc(100vh - 112px); color: var(--primary); - background-color: var(--panel); - border: 1px solid var(--border); overflow: hidden; } } @@ -23,22 +19,44 @@ height: 100%; } +.scrollbar { + display: flex; + justify-content: center; + background-color: rgba(0, 0, 0, 0.1); + width: 0.25rem; + border-radius: 0.375rem; + margin: 0.5rem; + opacity: 0; + transition: opacity 150ms 300ms; + right: -20px; + + &[data-scrolling] { + opacity: 1; + transition-duration: 75ms; + transition-delay: 0ms; + } + + &::before { + content: ''; + position: absolute; + width: 1.25rem; + height: 100%; + } +} + +.thumb { + width: 100%; + border-radius: inherit; + background-color: rgba(0, 0, 0, 0.2); +} + .viewport { overflow: scroll; height: 100%; } .content { - padding: 0 20px 20px; -} - -.logoContainer { - padding-left: 6px; - padding-top: 20px; -} - -.logo path { - fill: var(--primary); + padding: 0 20px 48px; } .menu { @@ -98,35 +116,3 @@ font-size: 14px; color: var(--secondary); } - -.scrollbar { - display: flex; - justify-content: center; - background-color: rgba(0, 0, 0, 0.1); - width: 0.25rem; - border-radius: 0.375rem; - margin: 0.5rem; - opacity: 0; - transition: opacity 150ms 300ms; - right: -20px; - - &[data-hovering], - &[data-scrolling] { - opacity: 1; - transition-duration: 75ms; - transition-delay: 0ms; - } - - &::before { - content: ''; - position: absolute; - width: 1.25rem; - height: 100%; - } -} - -.thumb { - width: 100%; - border-radius: inherit; - background-color: rgba(0, 0, 0, 0.2); -} diff --git a/docs-ui/src/components/Sidebar/docs.tsx b/docs-ui/src/components/Sidebar/docs.tsx deleted file mode 100644 index da501b151a..0000000000 --- a/docs-ui/src/components/Sidebar/docs.tsx +++ /dev/null @@ -1,82 +0,0 @@ -'use client'; - -import Link from 'next/link'; -import { components, overview, layoutComponents, theme } from '@/utils/data'; -import { motion } from 'motion/react'; -import styles from './Sidebar.module.css'; -import { usePathname } from 'next/navigation'; -import { Fragment } from 'react'; - -const data = [ - { - title: 'Overview', - content: overview, - url: '', - }, - { - title: 'Theme', - content: theme, - url: '/theme', - }, - { - title: 'Layout Components', - content: layoutComponents, - url: '/components', - }, - { - title: 'Components', - content: components, - url: '/components', - }, -]; - -export const Docs = () => { - const pathname = usePathname(); - const isPlayground = pathname.includes('/playground'); - - return ( - - {data.map(section => { - return ( - -
{section.title}
- - {section.content.map(item => { - const isActive = pathname === `${section.url}/${item.slug}`; - - return ( - -
{item.title}
-
- {item.status === 'alpha' && 'Alpha'} - {item.status === 'beta' && 'Beta'} - {item.status === 'inProgress' && 'In Progress'} - {item.status === 'stable' && 'Stable'} - {item.status === 'deprecated' && 'Deprecated'} -
- - ); - })} -
- ); - })} -
- ); -}; diff --git a/docs-ui/src/components/Sidebar/index.tsx b/docs-ui/src/components/Sidebar/index.tsx index b3fdbfe168..02308001d6 100644 --- a/docs-ui/src/components/Sidebar/index.tsx +++ b/docs-ui/src/components/Sidebar/index.tsx @@ -1,57 +1,92 @@ +'use client'; + import styles from './Sidebar.module.css'; -import { Docs } from './docs'; -import { Playground } from './playground'; -import Link from 'next/link'; +import { components, overview, layoutComponents, theme } from '@/utils/data'; import { ScrollArea } from '@base-ui-components/react/scroll-area'; +import Link from 'next/link'; +import { usePathname } from 'next/navigation'; +import { motion } from 'motion/react'; +import { Fragment } from 'react'; + +const data = [ + { + title: 'Overview', + content: overview, + url: '', + }, + { + title: 'Theme', + content: theme, + url: '/theme', + }, + { + title: 'Layout Components', + content: layoutComponents, + url: '/components', + }, + { + title: 'Components', + content: components, + url: '/components', + }, +]; export const Sidebar = () => { + const pathname = usePathname(); + const isPlayground = pathname.includes('/playground'); + return (
-
- - - - - - - - - - - - - - - - - - -
- - + + {data.map(section => { + return ( + +
{section.title}
+ + {section.content.map(item => { + const isActive = + pathname === `${section.url}/${item.slug}`; + + return ( + +
{item.title}
+
+ {item.status === 'alpha' && 'Alpha'} + {item.status === 'beta' && 'Beta'} + {item.status === 'inProgress' && 'In Progress'} + {item.status === 'stable' && 'Stable'} + {item.status === 'deprecated' && 'Deprecated'} +
+ + ); + })} +
+ ); + })} +
diff --git a/docs-ui/src/components/Sidebar/playground.tsx b/docs-ui/src/components/Sidebar/playground.tsx deleted file mode 100644 index d5dd9db892..0000000000 --- a/docs-ui/src/components/Sidebar/playground.tsx +++ /dev/null @@ -1,77 +0,0 @@ -'use client'; - -import { components } from '@/utils/data'; -import { Checkbox } from '@backstage/ui'; -import { motion } from 'motion/react'; -import styles from './Sidebar.module.css'; -import { usePathname } from 'next/navigation'; -import { screenSizes } from '@/utils/data'; -import { usePlayground } from '@/utils/playground-context'; - -export const Playground = () => { - const pathname = usePathname(); - const isPlayground = pathname.includes('/playground'); - const { - selectedScreenSizes, - setSelectedScreenSizes, - selectedComponents, - setSelectedComponents, - } = usePlayground(); - - const handleComponentCheckboxChange = (slug: string) => { - if (selectedComponents.find(item => item === slug)) { - const res = selectedComponents.filter(item => item !== slug); - setSelectedComponents(res); - } else { - setSelectedComponents([...selectedComponents, slug]); - } - }; - - const handleCheckboxChange = (slug: string) => { - if (selectedScreenSizes.find(item => item === slug)) { - const res = selectedScreenSizes.filter(item => item !== slug); - setSelectedScreenSizes(res); - } else { - setSelectedScreenSizes([...selectedScreenSizes, slug]); - } - }; - - return ( - -
Components
- {components.map(({ slug, title }) => ( -
-
{title}
- handleComponentCheckboxChange(slug)} - /> -
- ))} -
Screen sizes
- {screenSizes.map(({ slug, title }) => ( -
-
{title}
- handleCheckboxChange(slug)} - /> -
- ))} -
- ); -}; diff --git a/docs-ui/src/components/Toolbar/Toolbar.module.css b/docs-ui/src/components/Toolbar/Toolbar.module.css new file mode 100644 index 0000000000..d1f1b44a7f --- /dev/null +++ b/docs-ui/src/components/Toolbar/Toolbar.module.css @@ -0,0 +1,31 @@ +.toolbar { + position: fixed; + display: flex; + top: 0; + left: 332px; + right: 40px; + height: 112px; + z-index: 10; + align-items: center; + justify-content: space-between; + padding-left: 0.25rem; +} + +.left { + display: flex; + align-items: center; + gap: 0.75rem; +} + +.name { + margin-top: 3px; + font-size: 28px; + color: #26c9ad; + font-weight: 600; +} + +.actions { + display: flex; + align-items: center; + gap: 1rem; +} diff --git a/docs-ui/src/components/Toolbar/Toolbar.tsx b/docs-ui/src/components/Toolbar/Toolbar.tsx new file mode 100644 index 0000000000..5d7a5e3c47 --- /dev/null +++ b/docs-ui/src/components/Toolbar/Toolbar.tsx @@ -0,0 +1,30 @@ +import { ThemeSelector } from './theme'; +import { ThemeNameSelector } from './theme-name'; +import styles from './Toolbar.module.css'; +import { Nav } from './nav'; + +export const Toolbar = () => { + return ( +
+
+ + + +
Button
+
+
+ + +
+
+ ); +}; diff --git a/docs-ui/src/components/Toolbar/index.ts b/docs-ui/src/components/Toolbar/index.ts new file mode 100644 index 0000000000..f362defa5e --- /dev/null +++ b/docs-ui/src/components/Toolbar/index.ts @@ -0,0 +1 @@ +export { Toolbar } from './Toolbar'; diff --git a/docs-ui/src/components/Toolbar/index.tsx b/docs-ui/src/components/Toolbar/index.tsx deleted file mode 100644 index eac51f1857..0000000000 --- a/docs-ui/src/components/Toolbar/index.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { ThemeSelector } from './theme'; -import { ThemeNameSelector } from './theme-name'; -import styles from './styles.module.css'; -import { Nav } from './nav'; - -export const Toolbar = () => { - return ( -
-
-
-
- - -
-
- ); -}; diff --git a/docs-ui/src/components/Toolbar/styles.module.css b/docs-ui/src/components/Toolbar/styles.module.css deleted file mode 100644 index 5700e876ab..0000000000 --- a/docs-ui/src/components/Toolbar/styles.module.css +++ /dev/null @@ -1,22 +0,0 @@ -.toolbar { - position: sticky; - top: 16px; - left: 0; - right: 0; - border-radius: 0.5rem; - z-index: 10; - background-color: var(--panel); - height: 60px; - display: flex; - align-items: center; - justify-content: space-between; - padding: 0 1.5rem; - box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.025); - border: 1px solid var(--border); -} - -.actions { - display: flex; - align-items: center; - gap: 1rem; -} diff --git a/docs-ui/src/css/globals.css b/docs-ui/src/css/globals.css index f8ac189113..b9c82af302 100644 --- a/docs-ui/src/css/globals.css +++ b/docs-ui/src/css/globals.css @@ -26,8 +26,6 @@ } body { - display: flex; - flex-direction: row; background-color: var(--bg); color: var(--primary); font-family: var(--font-regular); diff --git a/docs-ui/src/css/page.module.css b/docs-ui/src/css/page.module.css deleted file mode 100644 index 3a0bb492d8..0000000000 --- a/docs-ui/src/css/page.module.css +++ /dev/null @@ -1,50 +0,0 @@ -.global { - width: 100%; -} - -.container { - width: 100%; - padding: 0 16px; -} - -@media (min-width: 768px) { - .container { - padding-left: 332px; - } -} - -.page { - flex: 1; -} - -.page p { - color: var(--primary); - font-size: 1rem; - line-height: 1.5rem; - margin-top: 0; - margin-bottom: 1rem; -} - -.content { - width: 100%; - max-width: 960px; - margin: 0 auto; - padding: 64px 24px 64px; -} - -.header { - width: 100%; - margin-bottom: 64px; -} - -.header img { - width: 100%; - height: auto; -} - -.pageContainer { - width: 100%; - max-width: 960px; - margin: 0 auto; - padding: 0 24px 64px; -} From 312a5512bb0d96fee4d1b99aaf2368df70c08a8e Mon Sep 17 00:00:00 2001 From: benjdlambert Date: Mon, 21 Jul 2025 10:31:00 +0200 Subject: [PATCH 07/16] chore: ammend the order in which the filters are loaded Signed-off-by: benjdlambert --- plugins/catalog/src/alpha/filters.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/plugins/catalog/src/alpha/filters.tsx b/plugins/catalog/src/alpha/filters.tsx index fcfbc394f2..d72e299fbb 100644 --- a/plugins/catalog/src/alpha/filters.tsx +++ b/plugins/catalog/src/alpha/filters.tsx @@ -133,13 +133,14 @@ const catalogListCatalogFilter = CatalogFilterBlueprint.makeWithOverrides({ }, }); +// this is the default order that the filters will be applied in export default [ - catalogTagCatalogFilter, catalogKindCatalogFilter, catalogTypeCatalogFilter, - catalogModeCatalogFilter, - catalogNamespaceCatalogFilter, - catalogLifecycleCatalogFilter, - catalogProcessingStatusCatalogFilter, catalogListCatalogFilter, + catalogModeCatalogFilter, + catalogLifecycleCatalogFilter, + catalogTagCatalogFilter, + catalogProcessingStatusCatalogFilter, + catalogNamespaceCatalogFilter, ]; From f4622e82f3a485e94368c41daa3de969b77939ff Mon Sep 17 00:00:00 2001 From: benjdlambert Date: Mon, 21 Jul 2025 10:31:50 +0200 Subject: [PATCH 08/16] chore: changeset Signed-off-by: benjdlambert --- .changeset/nice-actors-cheer.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/nice-actors-cheer.md diff --git a/.changeset/nice-actors-cheer.md b/.changeset/nice-actors-cheer.md new file mode 100644 index 0000000000..918148ffb8 --- /dev/null +++ b/.changeset/nice-actors-cheer.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog': patch +--- + +Adding a more sensible default order to the default filters From 2156d99515db9a6d102e74adf6102233121986f4 Mon Sep 17 00:00:00 2001 From: benjdlambert Date: Fri, 18 Jul 2025 12:11:24 +0200 Subject: [PATCH 09/16] feat: support filters in EntityHeader blueprint Signed-off-by: benjdlambert Signed-off-by: benjdlambert --- .../blueprints/EntityHeaderBlueprint.tsx | 32 ++++++++++++++++--- .../components/EntityLayout/EntityLayout.tsx | 19 +++++------ plugins/catalog/src/alpha/pages.tsx | 29 +++++++++++++---- 3 files changed, 60 insertions(+), 20 deletions(-) diff --git a/plugins/catalog-react/src/alpha/blueprints/EntityHeaderBlueprint.tsx b/plugins/catalog-react/src/alpha/blueprints/EntityHeaderBlueprint.tsx index 431197e753..73f09e4b22 100644 --- a/plugins/catalog-react/src/alpha/blueprints/EntityHeaderBlueprint.tsx +++ b/plugins/catalog-react/src/alpha/blueprints/EntityHeaderBlueprint.tsx @@ -19,22 +19,46 @@ import { coreExtensionData, ExtensionBoundary, } from '@backstage/frontend-plugin-api'; +import { EntityPredicate } from '../predicates/types'; +import { Entity } from '@backstage/catalog-model'; +import { resolveEntityFilterData } from './resolveEntityFilterData'; +import { createEntityPredicateSchema } from '../predicates/createEntityPredicateSchema'; +import { + entityFilterExpressionDataRef, + entityFilterFunctionDataRef, +} from './extensionData'; /** @alpha */ export const EntityHeaderBlueprint = createExtensionBlueprint({ kind: 'entity-header', - attachTo: { id: 'page:catalog/entity', input: 'header' }, + attachTo: { id: 'page:catalog/entity', input: 'headers' }, dataRefs: { + filterFunction: entityFilterFunctionDataRef, + filterExpression: entityFilterExpressionDataRef, element: coreExtensionData.reactElement, }, - output: [coreExtensionData.reactElement.optional()], + config: { + schema: { + filter: z => + z.union([z.string(), createEntityPredicateSchema(z)]).optional(), + }, + }, + output: [ + entityFilterFunctionDataRef.optional(), + entityFilterExpressionDataRef.optional(), + coreExtensionData.reactElement.optional(), + ], *factory( params: { loader: () => Promise; + filter?: string | EntityPredicate | ((entity: Entity) => boolean); }, - { node }, + { node, config }, ) { - const { loader } = params; + const { loader, filter } = params; + + yield* resolveEntityFilterData(filter, config, node); + if (loader) { yield coreExtensionData.reactElement( ExtensionBoundary.lazy(node, loader), diff --git a/plugins/catalog/src/alpha/components/EntityLayout/EntityLayout.tsx b/plugins/catalog/src/alpha/components/EntityLayout/EntityLayout.tsx index 750c8567ee..8f5838d545 100644 --- a/plugins/catalog/src/alpha/components/EntityLayout/EntityLayout.tsx +++ b/plugins/catalog/src/alpha/components/EntityLayout/EntityLayout.tsx @@ -102,13 +102,21 @@ export const EntityLayout = (props: EntityLayoutProps) => { UNSTABLE_contextMenuOptions, contextMenuItems, children, - header, NotFoundComponent, parentEntityRelations, } = props; const { kind } = useRouteRefParams(entityRouteRef); const { entity, loading, error } = useAsyncEntity(); + const header = props.header ?? ( + + ); + const routes = useElementFilter( children, elements => @@ -142,14 +150,7 @@ export const EntityLayout = (props: EntityLayoutProps) => { return ( - {header ?? ( - - )} + {!loading && header} {loading && } diff --git a/plugins/catalog/src/alpha/pages.tsx b/plugins/catalog/src/alpha/pages.tsx index 81ec0c5cb9..52b60e423d 100644 --- a/plugins/catalog/src/alpha/pages.tsx +++ b/plugins/catalog/src/alpha/pages.tsx @@ -36,6 +36,7 @@ import { import { rootRouteRef } from '../routes'; import { useEntityFromUrl } from '../components/CatalogEntityPage/useEntityFromUrl'; import { buildFilterFn } from './filter/FilterWrapper'; +import { Progress } from '@backstage/core-components'; export const catalogPage = PageBlueprint.makeWithOverrides({ inputs: { @@ -79,10 +80,10 @@ export const catalogPage = PageBlueprint.makeWithOverrides({ export const catalogEntityPage = PageBlueprint.makeWithOverrides({ name: 'entity', inputs: { - header: createExtensionInput( - [EntityHeaderBlueprint.dataRefs.element.optional()], - { singleton: true, optional: true }, - ), + headers: createExtensionInput([ + EntityHeaderBlueprint.dataRefs.element.optional(), + EntityHeaderBlueprint.dataRefs.filterFunction.optional(), + ]), contents: createExtensionInput([ coreExtensionData.reactElement, coreExtensionData.routePath, @@ -124,9 +125,19 @@ export const catalogEntityPage = PageBlueprint.makeWithOverrides({ { title: string; items: Array<(typeof inputs.contents)[0]> } >; - const header = inputs.header?.get( - EntityHeaderBlueprint.dataRefs.element, - ); + // Get available headers, sorted by if they have a filter function or not. + // TODO(blam): we should really have priority or some specificity here which can be used to sort the headers. + // That can be done with embedding the priority in the dataRef alongside the filter function. + const headers = inputs.headers + .map(header => ({ + element: header.get(EntityHeaderBlueprint.dataRefs.element), + filter: header.get(EntityHeaderBlueprint.dataRefs.filterFunction), + })) + .sort((a, b) => { + if (a.filter && !b.filter) return -1; + if (!a.filter && b.filter) return 1; + return 0; + }); let groups = Object.entries(defaultEntityContentGroups).reduce( (rest, group) => { @@ -169,6 +180,10 @@ export const catalogEntityPage = PageBlueprint.makeWithOverrides({ ? menuItems.filter(i => i.filter(entity)).map(i => i.element) : []; + const header = headers.find( + h => !h.filter || h.filter(entity!), + )?.element; + return ( Date: Fri, 18 Jul 2025 12:12:46 +0200 Subject: [PATCH 10/16] chore: add changesets Signed-off-by: benjdlambert --- .changeset/evil-phones-unite.md | 5 +++++ .changeset/nice-crabs-clean.md | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 .changeset/evil-phones-unite.md create mode 100644 .changeset/nice-crabs-clean.md diff --git a/.changeset/evil-phones-unite.md b/.changeset/evil-phones-unite.md new file mode 100644 index 0000000000..9a3e4ff151 --- /dev/null +++ b/.changeset/evil-phones-unite.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-react': patch +--- + +Support `filter` parameter on the `EntityHeaderBlueprint` diff --git a/.changeset/nice-crabs-clean.md b/.changeset/nice-crabs-clean.md new file mode 100644 index 0000000000..45690e98aa --- /dev/null +++ b/.changeset/nice-crabs-clean.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog': patch +--- + +Support multiple headers in new frontend system, and don't render a header until the entity has finished loading From 7058789375b0d9a3c1fa56f9d822872211cc0290 Mon Sep 17 00:00:00 2001 From: benjdlambert Date: Fri, 18 Jul 2025 12:22:13 +0200 Subject: [PATCH 11/16] chore: fix build and updating api-reports Signed-off-by: benjdlambert --- plugins/catalog-react/report-alpha.api.md | 48 ++++++++++++++++++----- plugins/catalog/report-alpha.api.md | 27 ++++++++----- plugins/catalog/src/alpha/pages.tsx | 1 - 3 files changed, 56 insertions(+), 20 deletions(-) diff --git a/plugins/catalog-react/report-alpha.api.md b/plugins/catalog-react/report-alpha.api.md index 8476eed695..4726b7d146 100644 --- a/plugins/catalog-react/report-alpha.api.md +++ b/plugins/catalog-react/report-alpha.api.md @@ -372,18 +372,48 @@ export const EntityHeaderBlueprint: ExtensionBlueprint<{ name: undefined; params: { loader: () => Promise; + filter?: string | EntityPredicate | ((entity: Entity) => boolean); }; - output: ConfigurableExtensionDataRef< - JSX_2.Element, - 'core.reactElement', - { - optional: true; - } - >; + output: + | ConfigurableExtensionDataRef< + (entity: Entity) => boolean, + 'catalog.entity-filter-function', + { + optional: true; + } + > + | ConfigurableExtensionDataRef< + string, + 'catalog.entity-filter-expression', + { + optional: true; + } + > + | ConfigurableExtensionDataRef< + JSX_2.Element, + 'core.reactElement', + { + optional: true; + } + >; inputs: {}; - config: {}; - configInput: {}; + config: { + filter: EntityPredicate | undefined; + }; + configInput: { + filter?: EntityPredicate | undefined; + }; dataRefs: { + filterFunction: ConfigurableExtensionDataRef< + (entity: Entity) => boolean, + 'catalog.entity-filter-function', + {} + >; + filterExpression: ConfigurableExtensionDataRef< + string, + 'catalog.entity-filter-expression', + {} + >; element: ConfigurableExtensionDataRef< JSX_2.Element, 'core.reactElement', diff --git a/plugins/catalog/report-alpha.api.md b/plugins/catalog/report-alpha.api.md index 4e00a5185e..81ebd10c3b 100644 --- a/plugins/catalog/report-alpha.api.md +++ b/plugins/catalog/report-alpha.api.md @@ -1097,17 +1097,24 @@ const _default: FrontendPlugin< } >; inputs: { - header: ExtensionInput< - ConfigurableExtensionDataRef< - JSX_2.Element, - 'core.reactElement', - { - optional: true; - } - >, + headers: ExtensionInput< + | ConfigurableExtensionDataRef< + (entity: Entity) => boolean, + 'catalog.entity-filter-function', + { + optional: true; + } + > + | ConfigurableExtensionDataRef< + JSX_2.Element, + 'core.reactElement', + { + optional: true; + } + >, { - singleton: true; - optional: true; + singleton: false; + optional: false; } >; contents: ExtensionInput< diff --git a/plugins/catalog/src/alpha/pages.tsx b/plugins/catalog/src/alpha/pages.tsx index 52b60e423d..f0c5316a84 100644 --- a/plugins/catalog/src/alpha/pages.tsx +++ b/plugins/catalog/src/alpha/pages.tsx @@ -36,7 +36,6 @@ import { import { rootRouteRef } from '../routes'; import { useEntityFromUrl } from '../components/CatalogEntityPage/useEntityFromUrl'; import { buildFilterFn } from './filter/FilterWrapper'; -import { Progress } from '@backstage/core-components'; export const catalogPage = PageBlueprint.makeWithOverrides({ inputs: { From 1bb3f48c177142bf71b9000b0a5f6a21aee779ce Mon Sep 17 00:00:00 2001 From: benjdlambert Date: Mon, 21 Jul 2025 10:41:17 +0200 Subject: [PATCH 12/16] feat: removing filter expression possibilities Signed-off-by: benjdlambert --- plugins/catalog-react/report-alpha.api.md | 7 +------ .../src/alpha/blueprints/EntityHeaderBlueprint.tsx | 6 ++---- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/plugins/catalog-react/report-alpha.api.md b/plugins/catalog-react/report-alpha.api.md index 4726b7d146..1db7a8e5e4 100644 --- a/plugins/catalog-react/report-alpha.api.md +++ b/plugins/catalog-react/report-alpha.api.md @@ -372,7 +372,7 @@ export const EntityHeaderBlueprint: ExtensionBlueprint<{ name: undefined; params: { loader: () => Promise; - filter?: string | EntityPredicate | ((entity: Entity) => boolean); + filter?: EntityPredicate | ((entity: Entity) => boolean); }; output: | ConfigurableExtensionDataRef< @@ -409,11 +409,6 @@ export const EntityHeaderBlueprint: ExtensionBlueprint<{ 'catalog.entity-filter-function', {} >; - filterExpression: ConfigurableExtensionDataRef< - string, - 'catalog.entity-filter-expression', - {} - >; element: ConfigurableExtensionDataRef< JSX_2.Element, 'core.reactElement', diff --git a/plugins/catalog-react/src/alpha/blueprints/EntityHeaderBlueprint.tsx b/plugins/catalog-react/src/alpha/blueprints/EntityHeaderBlueprint.tsx index 73f09e4b22..b83136dcd9 100644 --- a/plugins/catalog-react/src/alpha/blueprints/EntityHeaderBlueprint.tsx +++ b/plugins/catalog-react/src/alpha/blueprints/EntityHeaderBlueprint.tsx @@ -34,13 +34,11 @@ export const EntityHeaderBlueprint = createExtensionBlueprint({ attachTo: { id: 'page:catalog/entity', input: 'headers' }, dataRefs: { filterFunction: entityFilterFunctionDataRef, - filterExpression: entityFilterExpressionDataRef, element: coreExtensionData.reactElement, }, config: { schema: { - filter: z => - z.union([z.string(), createEntityPredicateSchema(z)]).optional(), + filter: z => createEntityPredicateSchema(z).optional(), }, }, output: [ @@ -51,7 +49,7 @@ export const EntityHeaderBlueprint = createExtensionBlueprint({ *factory( params: { loader: () => Promise; - filter?: string | EntityPredicate | ((entity: Entity) => boolean); + filter?: EntityPredicate | ((entity: Entity) => boolean); }, { node, config }, ) { From f40a5d11a284ff37d8df60c11dae93e5553b95f7 Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Mon, 21 Jul 2025 10:32:28 +0100 Subject: [PATCH 13/16] Improve page title Signed-off-by: Charles de Dreuille --- .../components/ChangelogComponent/index.tsx | 29 +++++++ .../components/PageTitle/PageTitle.module.css | 12 +++ docs-ui/src/components/PageTitle/index.tsx | 23 ++++++ .../src/components/Sidebar/Sidebar.module.css | 18 ++--- .../src/components/Toolbar/Toolbar.module.css | 4 +- docs-ui/src/components/Toolbar/Toolbar.tsx | 17 +++- docs-ui/src/components/Toolbar/nav.module.css | 78 ------------------- docs-ui/src/components/Toolbar/nav.tsx | 49 ------------ docs-ui/src/content/components/avatar.mdx | 8 +- docs-ui/src/content/components/box.mdx | 9 ++- .../src/content/components/button-icon.mdx | 8 +- .../src/content/components/button-link.mdx | 8 +- docs-ui/src/content/components/button.mdx | 26 ++++--- docs-ui/src/content/components/card.mdx | 8 +- docs-ui/src/content/components/checkbox.mdx | 8 +- .../src/content/components/collapsible.mdx | 8 +- docs-ui/src/content/components/container.mdx | 10 ++- docs-ui/src/content/components/flex.mdx | 9 ++- docs-ui/src/content/components/grid.mdx | 10 ++- docs-ui/src/content/components/heading.mdx | 8 +- docs-ui/src/content/components/icon.mdx | 8 +- docs-ui/src/content/components/link.mdx | 8 +- docs-ui/src/content/components/menu.mdx | 8 +- .../src/content/components/radio-group.mdx | 8 +- .../src/content/components/search-field.mdx | 7 +- docs-ui/src/content/components/select.mdx | 8 +- docs-ui/src/content/components/skeleton.mdx | 8 +- docs-ui/src/content/components/switch.mdx | 8 +- docs-ui/src/content/components/table.mdx | 7 +- docs-ui/src/content/components/tabs.mdx | 8 +- docs-ui/src/content/components/text-field.mdx | 8 +- docs-ui/src/content/components/text.mdx | 8 +- docs-ui/src/content/components/tooltip.mdx | 8 +- docs-ui/src/css/globals.css | 2 +- docs-ui/src/css/mdx.module.css | 9 ++- 35 files changed, 238 insertions(+), 225 deletions(-) create mode 100644 docs-ui/src/components/ChangelogComponent/index.tsx create mode 100644 docs-ui/src/components/PageTitle/PageTitle.module.css create mode 100644 docs-ui/src/components/PageTitle/index.tsx delete mode 100644 docs-ui/src/components/Toolbar/nav.module.css delete mode 100644 docs-ui/src/components/Toolbar/nav.tsx diff --git a/docs-ui/src/components/ChangelogComponent/index.tsx b/docs-ui/src/components/ChangelogComponent/index.tsx new file mode 100644 index 0000000000..d70e39e342 --- /dev/null +++ b/docs-ui/src/components/ChangelogComponent/index.tsx @@ -0,0 +1,29 @@ +import { changelog } from '@/utils/changelog'; +import { MDXRemote } from 'next-mdx-remote-client/rsc'; +import { formattedMDXComponents } from '@/mdx-components'; +import type { Component } from '@/utils/changelog'; + +export const ChangelogComponent = ({ component }: { component: Component }) => { + const componentChangelog = changelog.filter(c => + c.components.includes(component), + ); + + return ( + { + const prs = + change.prs.length > 0 && + change.prs + .map( + pr => + `[#${pr}](https://github.com/backstage/backstage/pull/${pr})`, + ) + .join(', '); + return `- \`${change.version}\` - ${change.description} ${prs}`; + }) + .join('\n')}`} + /> + ); +}; diff --git a/docs-ui/src/components/PageTitle/PageTitle.module.css b/docs-ui/src/components/PageTitle/PageTitle.module.css new file mode 100644 index 0000000000..f03b53db96 --- /dev/null +++ b/docs-ui/src/components/PageTitle/PageTitle.module.css @@ -0,0 +1,12 @@ +.container { + margin-bottom: 40px; +} + +.component { + font-size: 11px; + text-transform: uppercase; + font-weight: 500; + letter-spacing: 0.05em; + color: var(--secondary); + margin-bottom: 6px; +} diff --git a/docs-ui/src/components/PageTitle/index.tsx b/docs-ui/src/components/PageTitle/index.tsx new file mode 100644 index 0000000000..540e19eb36 --- /dev/null +++ b/docs-ui/src/components/PageTitle/index.tsx @@ -0,0 +1,23 @@ +import { MDXRemote } from 'next-mdx-remote-client/rsc'; +import { formattedMDXComponents } from '@/mdx-components'; +import styles from './PageTitle.module.css'; + +export const PageTitle = ({ + title, + description, + type = 'component', +}: { + title: string; + type?: string; + description: string; +}) => { + return ( +
+
{type}
+ +
+ ); +}; diff --git a/docs-ui/src/components/Sidebar/Sidebar.module.css b/docs-ui/src/components/Sidebar/Sidebar.module.css index 4fad36c74d..3687869490 100644 --- a/docs-ui/src/components/Sidebar/Sidebar.module.css +++ b/docs-ui/src/components/Sidebar/Sidebar.module.css @@ -73,11 +73,12 @@ } .sectionTitle { - font-size: 0.875rem; - font-weight: 600; - padding: 12px 0; - color: var(--primary); - margin-top: 24px; + font-size: 0.6875rem; + font-weight: 500; + padding: 0 12px 4px; + color: var(--secondary); + margin-top: 40px; + text-transform: uppercase; } .line { @@ -93,13 +94,12 @@ border-radius: 4px; &:hover { - background-color: var(--surface-1); - transition: background-color 0.2s ease-in-out; + background-color: white; } } .line.active { - background-color: var(--surface-1); + background-color: white; } .line.active .lineTitle { @@ -109,7 +109,7 @@ .lineTitle { font-size: 14px; font-weight: 400; - color: var(--secondary); + color: var(--primary); } .lineStatus { diff --git a/docs-ui/src/components/Toolbar/Toolbar.module.css b/docs-ui/src/components/Toolbar/Toolbar.module.css index d1f1b44a7f..d2803e1962 100644 --- a/docs-ui/src/components/Toolbar/Toolbar.module.css +++ b/docs-ui/src/components/Toolbar/Toolbar.module.css @@ -14,14 +14,14 @@ .left { display: flex; align-items: center; - gap: 0.75rem; + gap: 0.5rem; } .name { margin-top: 3px; font-size: 28px; color: #26c9ad; - font-weight: 600; + font-weight: 500; } .actions { diff --git a/docs-ui/src/components/Toolbar/Toolbar.tsx b/docs-ui/src/components/Toolbar/Toolbar.tsx index 5d7a5e3c47..e9c50fb269 100644 --- a/docs-ui/src/components/Toolbar/Toolbar.tsx +++ b/docs-ui/src/components/Toolbar/Toolbar.tsx @@ -1,9 +1,22 @@ +'use client'; + import { ThemeSelector } from './theme'; import { ThemeNameSelector } from './theme-name'; import styles from './Toolbar.module.css'; -import { Nav } from './nav'; +import { usePathname } from 'next/navigation'; +import { components, layoutComponents } from '@/utils/data'; +import { AnimatedName } from './AnimatedName'; export const Toolbar = () => { + const pathname = usePathname(); + const allComponents = [...layoutComponents, ...components]; + const isComponent = pathname.startsWith('/components'); + const componentSlug = pathname.replace('/components/', ''); + const findComponent = allComponents.find(c => c.slug === componentSlug); + + let name = 'UI'; + if (isComponent && findComponent) name = findComponent.title; + return (
@@ -19,7 +32,7 @@ export const Toolbar = () => { fill="#121212" /> -
Button
+
UI
diff --git a/docs-ui/src/components/Toolbar/nav.module.css b/docs-ui/src/components/Toolbar/nav.module.css deleted file mode 100644 index 56501f186e..0000000000 --- a/docs-ui/src/components/Toolbar/nav.module.css +++ /dev/null @@ -1,78 +0,0 @@ -.tabs { - display: none; -} - -@media (min-width: 768px) { - .tabs { - display: block; - height: 60px; - } -} - -.tabsTheme { - width: 142px; - border-radius: 0.375rem; - background-color: var(--bg); - transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out; -} - -.list { - display: flex; - position: relative; - z-index: 0; - gap: 2rem; -} - -.tab { - all: unset; - height: 60px; - color: var(--secondary); - font-size: 0.875rem; - font-weight: 600; - cursor: pointer; - - &:hover { - transition: color 0.2s ease-in-out; - color: var(--primary); - } - - &[data-selected] { - color: var(--primary); - - & p { - color: var(--primary); - } - } - - &:focus-visible { - position: relative; - - &::before { - content: ''; - position: absolute; - inset: 0.25rem 0; - border-radius: 0.25rem; - outline: 2px solid var(--panel); - outline-offset: -1px; - } - } -} - -.tab p { - color: var(--secondary) !important; -} - -.indicator { - position: absolute; - z-index: -1; - left: 0; - bottom: -1px; - translate: var(--active-tab-left) -50%; - width: var(--active-tab-width); - height: 1px; - border-radius: 0.25rem; - background-color: var(--primary); - transition-property: translate, width; - transition-duration: 200ms; - transition-timing-function: ease-in-out; -} diff --git a/docs-ui/src/components/Toolbar/nav.tsx b/docs-ui/src/components/Toolbar/nav.tsx deleted file mode 100644 index 017599581e..0000000000 --- a/docs-ui/src/components/Toolbar/nav.tsx +++ /dev/null @@ -1,49 +0,0 @@ -'use client'; - -import { Tabs } from '@base-ui-components/react/tabs'; -import { usePathname } from 'next/navigation'; -import { useRouter } from 'next/navigation'; -import styles from './nav.module.css'; - -export const Nav = () => { - const pathname = usePathname(); - const router = useRouter(); - - const onValueChange = (value: string) => { - if (value === 'docs') { - router.push('/'); - } else { - router.push('/playground'); - } - }; - - return ( - - - { - router.push('/'); - }} - > - Documentation - - { - router.push('/playground'); - }} - > - Playground - - - - - ); -}; diff --git a/docs-ui/src/content/components/avatar.mdx b/docs-ui/src/content/components/avatar.mdx index f5d39809ab..99b1da8264 100644 --- a/docs-ui/src/content/components/avatar.mdx +++ b/docs-ui/src/content/components/avatar.mdx @@ -9,10 +9,12 @@ import { snippetFallback, } from './avatar.props'; import { ComponentInfos } from '@/components/ComponentInfos'; +import { PageTitle } from '@/components/PageTitle'; -# Avatar - -An avatar component with a fallback for initials. + - +## Usage + + ## API reference @@ -102,3 +102,11 @@ If you want to use a button as a link, please use the `ButtonLink` component. preview={} code={buttonAsLinkSnippet} /> + +## Theming + +- `bui-Button` + +## Changelog + + diff --git a/docs-ui/src/content/components/card.mdx b/docs-ui/src/content/components/card.mdx index f08e68f88b..e0e49a2cd4 100644 --- a/docs-ui/src/content/components/card.mdx +++ b/docs-ui/src/content/components/card.mdx @@ -13,10 +13,12 @@ import { cardListRowSnippet, } from './card.props'; import { ComponentInfos } from '@/components/ComponentInfos'; +import { PageTitle } from '@/components/PageTitle'; -# Card - -A card component that can be used to display content in a box. + ` element. + diff --git a/docs-ui/src/content/components/tabs.mdx b/docs-ui/src/content/components/tabs.mdx index d3188b8d96..e2aa0f1ecd 100644 --- a/docs-ui/src/content/components/tabs.mdx +++ b/docs-ui/src/content/components/tabs.mdx @@ -11,10 +11,12 @@ import { tabsDefaultSnippet, } from './tabs.props'; import { ComponentInfos } from '@/components/ComponentInfos'; +import { PageTitle } from '@/components/PageTitle'; -# Tabs - -A component for toggling between related panels on the same page. + Date: Mon, 21 Jul 2025 11:25:48 +0100 Subject: [PATCH 14/16] Move Theming + Changelog to the bottom Signed-off-by: Charles de Dreuille --- docs-ui/package.json | 1 - .../src/app/(playground)/playground/page.tsx | 87 ------------------- .../(playground)/playground/styles.module.css | 36 -------- docs-ui/src/app/layout.module.css | 7 +- .../components/ChangelogComponent/index.tsx | 29 ++++--- .../ComponentInfos/ComponentInfos.tsx | 68 --------------- .../src/components/ComponentInfos/index.ts | 1 - .../src/components/ComponentInfos/types.ts | 9 -- .../components/CustomTheme/styles.module.css | 1 + docs-ui/src/components/Frame/index.tsx | 32 ------- .../src/components/Sidebar/Sidebar.module.css | 4 +- docs-ui/src/components/Theming/index.tsx | 26 ++++++ .../src/components/Toolbar/Toolbar.module.css | 23 +++-- docs-ui/src/components/Toolbar/Toolbar.tsx | 14 +-- .../components/Toolbar/theme-name.module.css | 10 +-- .../src/components/Toolbar/theme.module.css | 14 ++- docs-ui/src/content/components/avatar.mdx | 22 ++--- docs-ui/src/content/components/box.mdx | 11 ++- .../src/content/components/button-icon.mdx | 15 ++-- .../src/content/components/button-link.mdx | 15 ++-- docs-ui/src/content/components/button.mdx | 7 +- docs-ui/src/content/components/card.mdx | 15 ++-- docs-ui/src/content/components/checkbox.mdx | 15 ++-- .../src/content/components/collapsible.mdx | 19 ++-- docs-ui/src/content/components/container.mdx | 15 ++-- docs-ui/src/content/components/flex.mdx | 15 ++-- docs-ui/src/content/components/grid.mdx | 15 ++-- docs-ui/src/content/components/heading.mdx | 15 ++-- docs-ui/src/content/components/icon.mdx | 15 ++-- docs-ui/src/content/components/link.mdx | 23 ++--- docs-ui/src/content/components/menu.mdx | 31 ++----- .../src/content/components/radio-group.mdx | 16 ++-- .../src/content/components/search-field.mdx | 28 +++--- docs-ui/src/content/components/select.mdx | 24 ++--- docs-ui/src/content/components/skeleton.mdx | 15 ++-- docs-ui/src/content/components/switch.mdx | 15 ++-- docs-ui/src/content/components/tabs.mdx | 21 ++--- docs-ui/src/content/components/text-field.mdx | 26 +++--- docs-ui/src/content/components/text.mdx | 15 ++-- docs-ui/src/content/components/tooltip.mdx | 15 ++-- docs-ui/src/css/globals.css | 4 +- docs-ui/yarn.lock | 12 --- 42 files changed, 295 insertions(+), 506 deletions(-) delete mode 100644 docs-ui/src/app/(playground)/playground/page.tsx delete mode 100644 docs-ui/src/app/(playground)/playground/styles.module.css delete mode 100644 docs-ui/src/components/ComponentInfos/ComponentInfos.tsx delete mode 100644 docs-ui/src/components/ComponentInfos/index.ts delete mode 100644 docs-ui/src/components/ComponentInfos/types.ts delete mode 100644 docs-ui/src/components/Frame/index.tsx create mode 100644 docs-ui/src/components/Theming/index.tsx diff --git a/docs-ui/package.json b/docs-ui/package.json index 8049edac8d..74c5d59075 100644 --- a/docs-ui/package.json +++ b/docs-ui/package.json @@ -32,7 +32,6 @@ "prop-types": "^15.8.1", "react": "19.1.0", "react-dom": "19.1.0", - "react-frame-component": "^5.2.7", "shiki": "^1.26.1", "storybook": "^8.6.8" }, diff --git a/docs-ui/src/app/(playground)/playground/page.tsx b/docs-ui/src/app/(playground)/playground/page.tsx deleted file mode 100644 index 424cf2a707..0000000000 --- a/docs-ui/src/app/(playground)/playground/page.tsx +++ /dev/null @@ -1,87 +0,0 @@ -'use client'; - -import { ReactNode } from 'react'; -import { Grid, Flex, Text } from '../../../../../packages/ui'; -import { screenSizes } from '@/utils/data'; -import { Frame } from '@/components/Frame'; -import { usePlayground } from '@/utils/playground-context'; -import { - ButtonSnippet, - CheckboxSnippet, - HeadingSnippet, - TextSnippet, -} from '@/snippets/stories-snippets'; - -import styles from './styles.module.css'; - -export default function PlaygroundPage() { - const { selectedScreenSizes } = usePlayground(); - - const filteredScreenSizes = screenSizes.filter(item => - selectedScreenSizes.includes(item.slug), - ); - - if (filteredScreenSizes.length === 0) { - return ( -
- -
- ); - } - - return ( -
- {filteredScreenSizes.map(screenSize => ( -
- - {screenSize.title} - {screenSize.width}px - -
- - - -
-
- ))} -
- ); -} - -const Content = () => { - const { selectedComponents } = usePlayground(); - - return ( - - {selectedComponents.find(c => c === 'button') && ( - } title="Button" /> - )} - {selectedComponents.find(c => c === 'checkbox') && ( - } - title="Checkbox" - /> - )} - {selectedComponents.find(c => c === 'heading') && ( - } title="Heading" /> - )} - {selectedComponents.find(c => c === 'text') && ( - } title="Text" /> - )} - - ); -}; - -const Line = ({ content, title }: { content: ReactNode; title: string }) => { - return ( - - - {title} - - {content} - - ); -}; diff --git a/docs-ui/src/app/(playground)/playground/styles.module.css b/docs-ui/src/app/(playground)/playground/styles.module.css deleted file mode 100644 index 026e8a1bd4..0000000000 --- a/docs-ui/src/app/(playground)/playground/styles.module.css +++ /dev/null @@ -1,36 +0,0 @@ -.container { - height: 100vh; - display: flex; - flex-direction: row; - gap: 24px; - overflow-x: scroll; -} - -.containerEmpty { - padding: 78px 40px; -} - -.breakpointContainer { - flex-shrink: 0; - margin-top: 40px; - height: calc(100vh - 86px); - display: flex; - flex-direction: column; - gap: 8px; - - &:first-child { - margin-left: 48px; - } - - &:last-child { - margin-right: 48px; - } -} - -.breakpointContent { - height: 100%; - border-radius: 4px; - border: 1px solid var(--border); - background-color: var(--bg); - padding: 16px; -} diff --git a/docs-ui/src/app/layout.module.css b/docs-ui/src/app/layout.module.css index 895067c300..e7d9281c38 100644 --- a/docs-ui/src/app/layout.module.css +++ b/docs-ui/src/app/layout.module.css @@ -1,14 +1,15 @@ .container { position: relative; z-index: 20; - width: 100%; + width: calc(100% - 64px); margin-inline: 0 16px; + margin-left: 32px; + margin-right: 32px; margin-top: 112px; margin-bottom: 48px; padding-inline: 40px; padding-block: 48px; - background-color: white; - width: calc(100% - 32px); + background-color: var(--panel); border-radius: 0.5rem; } diff --git a/docs-ui/src/components/ChangelogComponent/index.tsx b/docs-ui/src/components/ChangelogComponent/index.tsx index d70e39e342..f8832b0731 100644 --- a/docs-ui/src/components/ChangelogComponent/index.tsx +++ b/docs-ui/src/components/ChangelogComponent/index.tsx @@ -11,19 +11,22 @@ export const ChangelogComponent = ({ component }: { component: Component }) => { return ( { - const prs = - change.prs.length > 0 && - change.prs - .map( - pr => - `[#${pr}](https://github.com/backstage/backstage/pull/${pr})`, - ) - .join(', '); - return `- \`${change.version}\` - ${change.description} ${prs}`; - }) - .join('\n')}`} + source={` + ## Changelog + + ${componentChangelog + ?.map(change => { + const prs = + change.prs.length > 0 && + change.prs + .map( + pr => + `[#${pr}](https://github.com/backstage/backstage/pull/${pr})`, + ) + .join(', '); + return `- \`${change.version}\` - ${change.description} ${prs}`; + }) + .join('\n')}`} /> ); }; diff --git a/docs-ui/src/components/ComponentInfos/ComponentInfos.tsx b/docs-ui/src/components/ComponentInfos/ComponentInfos.tsx deleted file mode 100644 index a29b01cba0..0000000000 --- a/docs-ui/src/components/ComponentInfos/ComponentInfos.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { Tabs } from '@/components/Tabs'; -import { CodeBlock } from '@/components/CodeBlock'; -import type { ComponentInfosProps } from './types'; -import styles from '@/css/mdx.module.css'; -import Link from 'next/link'; -import { changelog } from '@/utils/changelog'; -import { MDXRemote } from 'next-mdx-remote-client/rsc'; -import { formattedMDXComponents } from '@/mdx-components'; - -export const ComponentInfos = ({ - usageCode, - component, - classNames, -}: ComponentInfosProps) => { - const componentChangelog = changelog.filter(c => - c.components.includes(component), - ); - - return ( - - - Usage - {classNames && classNames.length > 0 && Theming} - Changelog - - - - - {classNames && classNames.length > 0 && ( - -

- We recommend starting with our{' '} - - global tokens - {' '} - to customize the library and align it with your brand. For - additional flexibility, you can use the provided class names for - each element listed below. -

- `- \`${className}\``) - .join('\n')}`} - /> -
- )} - - { - const prs = - change.prs.length > 0 && - change.prs - .map( - pr => - `[#${pr}](https://github.com/backstage/backstage/pull/${pr})`, - ) - .join(', '); - return `- \`${change.version}\` - ${change.description} ${prs}`; - }) - .join('\n')}`} - /> - -
- ); -}; diff --git a/docs-ui/src/components/ComponentInfos/index.ts b/docs-ui/src/components/ComponentInfos/index.ts deleted file mode 100644 index 04dbaeb1c6..0000000000 --- a/docs-ui/src/components/ComponentInfos/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { ComponentInfos } from './ComponentInfos'; diff --git a/docs-ui/src/components/ComponentInfos/types.ts b/docs-ui/src/components/ComponentInfos/types.ts deleted file mode 100644 index 8814ff479a..0000000000 --- a/docs-ui/src/components/ComponentInfos/types.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { Component } from '@/utils/changelog'; -import { ReactNode } from 'react'; - -export interface ComponentInfosProps { - usageCode?: string; - classNames?: string[]; - component: Component; - children: ReactNode; -} diff --git a/docs-ui/src/components/CustomTheme/styles.module.css b/docs-ui/src/components/CustomTheme/styles.module.css index 3f0a5eb14e..05604c48be 100644 --- a/docs-ui/src/components/CustomTheme/styles.module.css +++ b/docs-ui/src/components/CustomTheme/styles.module.css @@ -1,5 +1,6 @@ .container { position: fixed; + z-index: 100; bottom: 16px; right: 16px; width: 240px; diff --git a/docs-ui/src/components/Frame/index.tsx b/docs-ui/src/components/Frame/index.tsx deleted file mode 100644 index d6255401dd..0000000000 --- a/docs-ui/src/components/Frame/index.tsx +++ /dev/null @@ -1,32 +0,0 @@ -'use client'; - -import { useEffect, useState } from 'react'; -import ReactFrame from 'react-frame-component'; - -export const Frame = ({ children }: { children: React.ReactNode }) => { - const [show, setShow] = useState(false); - - useEffect(() => { - setShow(true); - }, []); - - if (!show) return null; - - return ( -
`} - mountTarget=".frame-root" - head={ - <> - - - - - } - > - {children} -
- ); -}; diff --git a/docs-ui/src/components/Sidebar/Sidebar.module.css b/docs-ui/src/components/Sidebar/Sidebar.module.css index 3687869490..b658255b32 100644 --- a/docs-ui/src/components/Sidebar/Sidebar.module.css +++ b/docs-ui/src/components/Sidebar/Sidebar.module.css @@ -94,12 +94,12 @@ border-radius: 4px; &:hover { - background-color: white; + background-color: var(--action); } } .line.active { - background-color: white; + background-color: var(--action); } .line.active .lineTitle { diff --git a/docs-ui/src/components/Theming/index.tsx b/docs-ui/src/components/Theming/index.tsx new file mode 100644 index 0000000000..f015804756 --- /dev/null +++ b/docs-ui/src/components/Theming/index.tsx @@ -0,0 +1,26 @@ +import { MDXRemote } from 'next-mdx-remote-client/rsc'; +import { formattedMDXComponents } from '@/mdx-components'; +import { Component } from '@/utils/changelog'; +import { componentDefinitions } from '../../../../packages/ui/src/utils/componentDefinitions'; + +export function Theming({ component }: { component: Component }) { + const componentDefinition = componentDefinitions[component]; + + if (!componentDefinition) { + return null; + } + + const classNames = componentDefinition.classNames; + + // Convert classNames object values to array + const classNameArray = Object.values(classNames); + + return ( + `- \`${className}\``).join('\n')} + `} + /> + ); +} diff --git a/docs-ui/src/components/Toolbar/Toolbar.module.css b/docs-ui/src/components/Toolbar/Toolbar.module.css index d2803e1962..8142c5464e 100644 --- a/docs-ui/src/components/Toolbar/Toolbar.module.css +++ b/docs-ui/src/components/Toolbar/Toolbar.module.css @@ -2,8 +2,8 @@ position: fixed; display: flex; top: 0; - left: 332px; - right: 40px; + left: 32px; + right: 32px; height: 112px; z-index: 10; align-items: center; @@ -11,6 +11,13 @@ padding-left: 0.25rem; } +@media (min-width: 960px) { + .toolbar { + left: 332px; + right: 40px; + } +} + .left { display: flex; align-items: center; @@ -25,7 +32,13 @@ } .actions { - display: flex; - align-items: center; - gap: 1rem; + display: none; +} + +@media (min-width: 600px) { + .actions { + display: flex; + align-items: center; + gap: 1rem; + } } diff --git a/docs-ui/src/components/Toolbar/Toolbar.tsx b/docs-ui/src/components/Toolbar/Toolbar.tsx index e9c50fb269..952b48f5ac 100644 --- a/docs-ui/src/components/Toolbar/Toolbar.tsx +++ b/docs-ui/src/components/Toolbar/Toolbar.tsx @@ -3,20 +3,8 @@ import { ThemeSelector } from './theme'; import { ThemeNameSelector } from './theme-name'; import styles from './Toolbar.module.css'; -import { usePathname } from 'next/navigation'; -import { components, layoutComponents } from '@/utils/data'; -import { AnimatedName } from './AnimatedName'; export const Toolbar = () => { - const pathname = usePathname(); - const allComponents = [...layoutComponents, ...components]; - const isComponent = pathname.startsWith('/components'); - const componentSlug = pathname.replace('/components/', ''); - const findComponent = allComponents.find(c => c.slug === componentSlug); - - let name = 'UI'; - if (isComponent && findComponent) name = findComponent.title; - return (
@@ -29,7 +17,7 @@ export const Toolbar = () => { >
UI
diff --git a/docs-ui/src/components/Toolbar/theme-name.module.css b/docs-ui/src/components/Toolbar/theme-name.module.css index 02644e8ea0..58471b8fd7 100644 --- a/docs-ui/src/components/Toolbar/theme-name.module.css +++ b/docs-ui/src/components/Toolbar/theme-name.module.css @@ -4,20 +4,20 @@ align-items: center; justify-content: space-between; gap: 0.75rem; - height: 2rem; - padding-left: 0.875rem; - padding-right: 0.75rem; + height: 3rem; + padding-left: 1.25rem; + padding-right: 1rem; margin: 0; outline: 0; border: 1px solid var(--color-gray-200); - border-radius: 0.375rem; + border-radius: 3rem; font-family: inherit; font-size: 1rem; line-height: 1.5rem; color: var(--color-gray-900); cursor: pointer; user-select: none; - background-color: var(--surface-1); + background-color: var(--action); &:focus-visible { outline: 2px solid var(--color-blue); diff --git a/docs-ui/src/components/Toolbar/theme.module.css b/docs-ui/src/components/Toolbar/theme.module.css index a7895ad840..c5490a72d7 100644 --- a/docs-ui/src/components/Toolbar/theme.module.css +++ b/docs-ui/src/components/Toolbar/theme.module.css @@ -1,20 +1,17 @@ .tabs { border-radius: 0.375rem; width: 100%; - background-color: var(--surface-1); } .tabsTheme { width: 100px; border-radius: 0.375rem; - background-color: var(--surface-1); } .list { display: flex; position: relative; z-index: 0; - padding-inline: 0.25rem; gap: 0.25rem; } @@ -29,9 +26,10 @@ appearance: none; color: var(--secondary); user-select: none; - height: 2rem; flex: 1; cursor: pointer; + width: 3rem; + height: 3rem; &[data-selected] { color: var(--primary); @@ -55,7 +53,7 @@ position: absolute; inset: 0.25rem 0; border-radius: 0.25rem; - outline: 2px solid var(--panel); + outline: 2px solid var(--action); outline-offset: -1px; } } @@ -72,9 +70,9 @@ top: 50%; translate: var(--active-tab-left) -50%; width: var(--active-tab-width); - height: 1.5rem; - border-radius: 0.25rem; - background-color: var(--panel); + height: 3rem; + border-radius: 3rem; + background-color: var(--action); transition-property: translate, width; transition-duration: 200ms; transition-timing-function: ease-in-out; diff --git a/docs-ui/src/content/components/avatar.mdx b/docs-ui/src/content/components/avatar.mdx index 99b1da8264..be1fb070d1 100644 --- a/docs-ui/src/content/components/avatar.mdx +++ b/docs-ui/src/content/components/avatar.mdx @@ -8,8 +8,9 @@ import { snippetSizes, snippetFallback, } from './avatar.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; `} /> - +## Usage + + ## API reference @@ -65,3 +57,7 @@ If the image is not available, the avatar will show the initials of the name. preview={} code={snippetFallback} /> + + + + diff --git a/docs-ui/src/content/components/box.mdx b/docs-ui/src/content/components/box.mdx index 0c638ac95b..84fca48349 100644 --- a/docs-ui/src/content/components/box.mdx +++ b/docs-ui/src/content/components/box.mdx @@ -10,8 +10,9 @@ import { boxResponsiveSnippet, } from './box.props'; import { spacingPropDefs } from '@/utils/propDefs'; -import { ComponentInfos } from '@/components/ComponentInfos'; import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; - +## Usage + + ## API reference @@ -56,3 +59,7 @@ A simple example of how to use the Box component. Here's a view when buttons are responsive. + + + + diff --git a/docs-ui/src/content/components/button-icon.mdx b/docs-ui/src/content/components/button-icon.mdx index 3583acd6a9..e1f27e0601 100644 --- a/docs-ui/src/content/components/button-icon.mdx +++ b/docs-ui/src/content/components/button-icon.mdx @@ -12,8 +12,9 @@ import { buttonIconResponsiveSnippet, buttonIconAsLinkSnippet, } from './button-icon.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; - +## Usage + + ## API reference @@ -80,3 +79,7 @@ Here's a view when buttons are disabled. Here's a view when buttons are responsive. + + + + diff --git a/docs-ui/src/content/components/button-link.mdx b/docs-ui/src/content/components/button-link.mdx index d52c1aadb3..5ce538838d 100644 --- a/docs-ui/src/content/components/button-link.mdx +++ b/docs-ui/src/content/components/button-link.mdx @@ -11,8 +11,9 @@ import { buttonLinkDisabledSnippet, buttonLinkResponsiveSnippet, } from './button-link.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; - +## Usage + + ## API reference @@ -91,3 +90,7 @@ Here's a view when buttons are disabled. Here's a view when buttons are responsive. + + + + diff --git a/docs-ui/src/content/components/button.mdx b/docs-ui/src/content/components/button.mdx index 8e39a485d3..a25115012b 100644 --- a/docs-ui/src/content/components/button.mdx +++ b/docs-ui/src/content/components/button.mdx @@ -14,6 +14,7 @@ import { } from './button.props'; import { ChangelogComponent } from '@/components/ChangelogComponent'; import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; -## Theming - -- `bui-Button` - -## Changelog + diff --git a/docs-ui/src/content/components/card.mdx b/docs-ui/src/content/components/card.mdx index e0e49a2cd4..06c3a5bc2e 100644 --- a/docs-ui/src/content/components/card.mdx +++ b/docs-ui/src/content/components/card.mdx @@ -12,8 +12,9 @@ import { cardLongBodySnippet, cardListRowSnippet, } from './card.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; - +## Usage + + ## API reference @@ -84,3 +83,7 @@ Here's a view when card has a list. code={cardListRowSnippet} open /> + + + + diff --git a/docs-ui/src/content/components/checkbox.mdx b/docs-ui/src/content/components/checkbox.mdx index 82ece3942b..5770396ebb 100644 --- a/docs-ui/src/content/components/checkbox.mdx +++ b/docs-ui/src/content/components/checkbox.mdx @@ -8,8 +8,9 @@ import { checkboxDefaultSnippet, checkboxVariantsSnippet, } from './checkbox.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; - +## Usage + + ## API reference @@ -46,3 +45,7 @@ Here's a view when checkboxes have different variants. preview={} code={checkboxVariantsSnippet} /> + + + + diff --git a/docs-ui/src/content/components/collapsible.mdx b/docs-ui/src/content/components/collapsible.mdx index 199232545e..948da323fe 100644 --- a/docs-ui/src/content/components/collapsible.mdx +++ b/docs-ui/src/content/components/collapsible.mdx @@ -11,8 +11,9 @@ import { collapsibleTriggerSnippet, collapsibleOpenSnippet, } from './collapsible.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; - +## Usage + + ## API reference @@ -71,3 +66,7 @@ Open the panel by default by setting the `defaultOpen` prop to `true`. preview={} code={collapsibleOpenSnippet} /> + + + + diff --git a/docs-ui/src/content/components/container.mdx b/docs-ui/src/content/components/container.mdx index 32fd0d5ca8..05615cb1c2 100644 --- a/docs-ui/src/content/components/container.mdx +++ b/docs-ui/src/content/components/container.mdx @@ -9,8 +9,9 @@ import { containerSimpleSnippet, containerResponsiveSnippet, } from './container.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; - +## Usage + + ## API reference @@ -48,3 +47,7 @@ The Container component also supports responsive values, making it easy to create responsive designs. + + + + diff --git a/docs-ui/src/content/components/flex.mdx b/docs-ui/src/content/components/flex.mdx index ff12320449..89cd2e380a 100644 --- a/docs-ui/src/content/components/flex.mdx +++ b/docs-ui/src/content/components/flex.mdx @@ -12,8 +12,9 @@ import { flexAlignSnippet, } from './flex.props'; import { spacingPropDefs } from '@/utils/propDefs'; -import { ComponentInfos } from '@/components/ComponentInfos'; import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; - +## Usage + + ## API reference @@ -63,3 +62,7 @@ The Flex component also supports responsive alignment, making it easy to create responsive designs. + + + + diff --git a/docs-ui/src/content/components/grid.mdx b/docs-ui/src/content/components/grid.mdx index 6a1c6bd041..0ffdba6a66 100644 --- a/docs-ui/src/content/components/grid.mdx +++ b/docs-ui/src/content/components/grid.mdx @@ -14,8 +14,9 @@ import { gridResponsiveSnippet, gridStartEndSnippet, } from './grid.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; - +## Usage + + ## API reference @@ -93,3 +92,7 @@ responsive designs. The start and end props can be used to position the item in the grid. + + + + diff --git a/docs-ui/src/content/components/heading.mdx b/docs-ui/src/content/components/heading.mdx index 07c161de75..de724d0b00 100644 --- a/docs-ui/src/content/components/heading.mdx +++ b/docs-ui/src/content/components/heading.mdx @@ -10,8 +10,9 @@ import { headingTruncateSnippet, headingResponsiveSnippet, } from './heading.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; - +## Usage + + ## API reference @@ -66,3 +65,7 @@ You can also use the `variant` prop to change the appearance of the text based on the screen size. + + + + diff --git a/docs-ui/src/content/components/icon.mdx b/docs-ui/src/content/components/icon.mdx index fea93195c0..91860a7e5e 100644 --- a/docs-ui/src/content/components/icon.mdx +++ b/docs-ui/src/content/components/icon.mdx @@ -7,8 +7,9 @@ import { iconUsageSnippet, iconDefaultSnippet, } from './icon.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; - +## Usage + + ## API reference + + + + diff --git a/docs-ui/src/content/components/link.mdx b/docs-ui/src/content/components/link.mdx index 97bb6482aa..ad0c1e0eaf 100644 --- a/docs-ui/src/content/components/link.mdx +++ b/docs-ui/src/content/components/link.mdx @@ -13,8 +13,9 @@ import { linkVariantsSnippet, linkWeightsSnippet, } from './link.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; - +## Usage + + ## API reference @@ -71,3 +62,7 @@ Here's a view when links have different weights. preview={} code={linkWeightsSnippet} /> + + + + diff --git a/docs-ui/src/content/components/menu.mdx b/docs-ui/src/content/components/menu.mdx index 153b2bcd2b..c1b67b5034 100644 --- a/docs-ui/src/content/components/menu.mdx +++ b/docs-ui/src/content/components/menu.mdx @@ -13,8 +13,9 @@ import { menuHoverSnippet, menuSubmenuSnippet, } from './menu.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; - +## Usage + + ## API reference @@ -105,3 +88,7 @@ You can nest menus to create a more complex navigation structure. preview={} code={menuSubmenuSnippet} /> + + + + diff --git a/docs-ui/src/content/components/radio-group.mdx b/docs-ui/src/content/components/radio-group.mdx index 8b3ddf1a8f..ab3d28ad81 100644 --- a/docs-ui/src/content/components/radio-group.mdx +++ b/docs-ui/src/content/components/radio-group.mdx @@ -12,8 +12,10 @@ import { radioGroupValidationSnippet, radioGroupReadOnlySnippet, } from './radio-group.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; +import { CodeBlock } from '@/components/CodeBlock'; - +## Usage + + ## API reference @@ -98,3 +98,7 @@ You can make the radio group read only by adding the `isReadOnly` prop to the `R preview={} code={radioGroupReadOnlySnippet} /> + + + + diff --git a/docs-ui/src/content/components/search-field.mdx b/docs-ui/src/content/components/search-field.mdx index a11b0a3d40..cc8ae98685 100644 --- a/docs-ui/src/content/components/search-field.mdx +++ b/docs-ui/src/content/components/search-field.mdx @@ -8,7 +8,10 @@ import { searchFieldSizesSnippet, searchFieldDescriptionSnippet, } from './search-field.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; +import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; +import { CodeBlock } from '@/components/CodeBlock'; - +## Usage + + ## API reference @@ -68,3 +58,7 @@ Here's a simple SearchField with a description. preview={} code={searchFieldDescriptionSnippet} /> + + + + diff --git a/docs-ui/src/content/components/select.mdx b/docs-ui/src/content/components/select.mdx index 0a693fec40..09a852e871 100644 --- a/docs-ui/src/content/components/select.mdx +++ b/docs-ui/src/content/components/select.mdx @@ -12,8 +12,9 @@ import { selectResponsiveSnippet, selectIconSnippet, } from './select.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; - +## Usage + + ## API reference @@ -102,3 +92,7 @@ Here's a view when the select is disabled. Here's a view when the select is responsive. + + + + diff --git a/docs-ui/src/content/components/skeleton.mdx b/docs-ui/src/content/components/skeleton.mdx index 03a2664898..f0d3fbc39a 100644 --- a/docs-ui/src/content/components/skeleton.mdx +++ b/docs-ui/src/content/components/skeleton.mdx @@ -9,8 +9,9 @@ import { skeletonDemo1Snippet, skeletonDemo2Snippet, } from './skeleton.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; - +## Usage + + ## API reference @@ -59,3 +58,7 @@ You can use a mix of different sizes to create a more complex skeleton. code={skeletonDemo2Snippet} open /> + + + + diff --git a/docs-ui/src/content/components/switch.mdx b/docs-ui/src/content/components/switch.mdx index a402b2466a..acf588e37d 100644 --- a/docs-ui/src/content/components/switch.mdx +++ b/docs-ui/src/content/components/switch.mdx @@ -3,8 +3,9 @@ import { Snippet } from '@/components/Snippet'; import { CodeBlock } from '@/components/CodeBlock'; import { SwitchSnippet } from '@/snippets/stories-snippets'; import { switchPropDefs, snippetUsage } from './switch.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; `} /> - +## Usage + + ## API reference @@ -41,3 +40,7 @@ A switch can be disabled using the `isDisabled` prop. preview={} code={``} /> + + + + diff --git a/docs-ui/src/content/components/tabs.mdx b/docs-ui/src/content/components/tabs.mdx index e2aa0f1ecd..dd0552b436 100644 --- a/docs-ui/src/content/components/tabs.mdx +++ b/docs-ui/src/content/components/tabs.mdx @@ -10,8 +10,9 @@ import { tabsUsageSnippet, tabsDefaultSnippet, } from './tabs.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; - +## Usage + + ## API reference @@ -61,3 +54,7 @@ An individual interactive tab button that toggles the corresponding panel. Rende A panel displayed when the corresponding tab is active. Renders a `
` element. + + + + diff --git a/docs-ui/src/content/components/text-field.mdx b/docs-ui/src/content/components/text-field.mdx index 922b170551..ad90783ffb 100644 --- a/docs-ui/src/content/components/text-field.mdx +++ b/docs-ui/src/content/components/text-field.mdx @@ -8,8 +8,10 @@ import { textFieldSizesSnippet, textFieldDescriptionSnippet, } from './text-field.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; +import { CodeBlock } from '@/components/CodeBlock'; - +## Usage + + ## API reference @@ -68,3 +58,7 @@ Here's a simple TextField with a description. preview={} code={textFieldDescriptionSnippet} /> + + + + diff --git a/docs-ui/src/content/components/text.mdx b/docs-ui/src/content/components/text.mdx index 2b64c7ca12..d8d095e61d 100644 --- a/docs-ui/src/content/components/text.mdx +++ b/docs-ui/src/content/components/text.mdx @@ -11,8 +11,9 @@ import { textTruncateSnippet, textResponsiveSnippet, } from './text.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; - +## Usage + + ## API reference @@ -76,3 +75,7 @@ You can also use the `variant` prop to change the appearance of the text based on the screen size. + + + + diff --git a/docs-ui/src/content/components/tooltip.mdx b/docs-ui/src/content/components/tooltip.mdx index d6ea3fb4e4..dd2add5308 100644 --- a/docs-ui/src/content/components/tooltip.mdx +++ b/docs-ui/src/content/components/tooltip.mdx @@ -8,8 +8,9 @@ import { tooltipTriggerPropDefs, tooltipPropDefs, } from './tooltip.props'; -import { ComponentInfos } from '@/components/ComponentInfos'; import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; - +## Usage + + ## API reference @@ -42,3 +41,7 @@ The trigger will wrap both the trigger and the tooltip. The tooltip will wrap the content of the tooltip. + + + + diff --git a/docs-ui/src/css/globals.css b/docs-ui/src/css/globals.css index 24dcc78f3f..334e6a870a 100644 --- a/docs-ui/src/css/globals.css +++ b/docs-ui/src/css/globals.css @@ -3,6 +3,7 @@ --panel: #fff; --primary: #000; --secondary: #929292; + --action: #fff; --link: #4f5ce0; --font-regular: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', @@ -17,9 +18,10 @@ [data-theme='dark'] { --bg: #000; - --panel: #1a1a1a; + --panel: #181818; --primary: #fff; --secondary: #818181; + --action: #202020; --link: #4856e8; --border: #2a2a2a; --surface-1: #282828; diff --git a/docs-ui/yarn.lock b/docs-ui/yarn.lock index 7fbef814a6..56895e3b7b 100644 --- a/docs-ui/yarn.lock +++ b/docs-ui/yarn.lock @@ -2321,7 +2321,6 @@ __metadata: prop-types: "npm:^15.8.1" react: "npm:19.1.0" react-dom: "npm:19.1.0" - react-frame-component: "npm:^5.2.7" shiki: "npm:^1.26.1" storybook: "npm:^8.6.8" typescript: "npm:^5" @@ -5587,17 +5586,6 @@ __metadata: languageName: node linkType: hard -"react-frame-component@npm:^5.2.7": - version: 5.2.7 - resolution: "react-frame-component@npm:5.2.7" - peerDependencies: - prop-types: ^15.5.9 - react: ">= 16.3" - react-dom: ">= 16.3" - checksum: 10/bedee0c25075cbfb6d592991937640a9c8680f9017284e73ced338cc07348b3efc99121052b60ba0923d3d4ec1ed050348ddec452f059e0b947f6bff1d5bfe24 - languageName: node - linkType: hard - "react-is@npm:^16.13.1": version: 16.13.1 resolution: "react-is@npm:16.13.1" From b2fe33e7fdd36e8d4f276b28275da993845c55da Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Mon, 21 Jul 2025 12:07:18 +0100 Subject: [PATCH 15/16] Automatic version number Signed-off-by: Charles de Dreuille --- docs-ui/package.json | 1 + docs-ui/src/app/layout.tsx | 24 +++++++++++++-- .../src/components/Sidebar/Sidebar.module.css | 29 ++++++++++++++++++- docs-ui/src/components/Sidebar/index.tsx | 21 +++++++++++++- docs-ui/yarn.lock | 10 +++++++ 5 files changed, 81 insertions(+), 4 deletions(-) diff --git a/docs-ui/package.json b/docs-ui/package.json index 74c5d59075..6fd29e0678 100644 --- a/docs-ui/package.json +++ b/docs-ui/package.json @@ -22,6 +22,7 @@ "@mdx-js/loader": "^3.1.0", "@mdx-js/react": "^3.1.0", "@next/mdx": "15.3.4", + "@remixicon/react": "^4.6.0", "@storybook/react": "^8.6.8", "@uiw/codemirror-themes": "^4.23.7", "@uiw/react-codemirror": "^4.23.7", diff --git a/docs-ui/src/app/layout.tsx b/docs-ui/src/app/layout.tsx index 7ee30ddfa0..697f990587 100644 --- a/docs-ui/src/app/layout.tsx +++ b/docs-ui/src/app/layout.tsx @@ -15,11 +15,31 @@ export const metadata: Metadata = { metadataBase: new URL('https://ui.backstage.io'), }; -export default function RootLayout({ +async function getLatestPackageVersion(): Promise { + try { + const response = await fetch('https://registry.npmjs.org/@backstage/ui', { + next: { revalidate: 3600 }, // Cache for 1 hour + }); + + if (!response.ok) { + throw new Error('Failed to fetch package info'); + } + + const data = await response.json(); + return data['dist-tags']?.latest; + } catch (error) { + console.error('Error fetching package version:', error); + return '0.0.0'; + } +} + +export default async function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { + const packageVersion = await getLatestPackageVersion(); + return ( - +
{children}
diff --git a/docs-ui/src/components/Sidebar/Sidebar.module.css b/docs-ui/src/components/Sidebar/Sidebar.module.css index b658255b32..2b88945c47 100644 --- a/docs-ui/src/components/Sidebar/Sidebar.module.css +++ b/docs-ui/src/components/Sidebar/Sidebar.module.css @@ -15,6 +15,33 @@ } } +.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%; } @@ -56,7 +83,7 @@ } .content { - padding: 0 20px 48px; + padding: 0 20px 64px; } .menu { diff --git a/docs-ui/src/components/Sidebar/index.tsx b/docs-ui/src/components/Sidebar/index.tsx index 02308001d6..4d86398ef7 100644 --- a/docs-ui/src/components/Sidebar/index.tsx +++ b/docs-ui/src/components/Sidebar/index.tsx @@ -7,6 +7,7 @@ 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 = [ { @@ -31,12 +32,30 @@ const data = [ }, ]; -export const Sidebar = () => { +interface SidebarProps { + version: string; +} + +export const Sidebar = ({ version }: SidebarProps) => { const pathname = usePathname(); const isPlayground = pathname.includes('/playground'); return (
+
+ Version {version} + +
diff --git a/docs-ui/yarn.lock b/docs-ui/yarn.lock index 56895e3b7b..22531f1a3b 100644 --- a/docs-ui/yarn.lock +++ b/docs-ui/yarn.lock @@ -907,6 +907,15 @@ __metadata: languageName: node linkType: hard +"@remixicon/react@npm:^4.6.0": + version: 4.6.0 + resolution: "@remixicon/react@npm:4.6.0" + peerDependencies: + react: ">=18.2.0" + checksum: 10/d92c8131734062fca8d82d55dd8f3f4e28cb72c5eefda528c8aba5f3298f0c847342eecdbd7787d6da5af21b699d735f6cf27f151f0c982c1c9f06a78b235c94 + languageName: node + linkType: hard + "@rtsao/scc@npm:^1.1.0": version: 1.1.0 resolution: "@rtsao/scc@npm:1.1.0" @@ -2302,6 +2311,7 @@ __metadata: "@mdx-js/loader": "npm:^3.1.0" "@mdx-js/react": "npm:^3.1.0" "@next/mdx": "npm:15.3.4" + "@remixicon/react": "npm:^4.6.0" "@storybook/react": "npm:^8.6.8" "@types/mdx": "npm:^2.0.13" "@types/node": "npm:^20" From 7ef594bf197b94b0bbc229f34ca64a509408b3f4 Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Mon, 21 Jul 2025 12:30:30 +0100 Subject: [PATCH 16/16] Improve theming Signed-off-by: Charles de Dreuille --- docs-ui/src/app/(docs)/layout.module.css | 5 - docs-ui/src/app/(docs)/layout.tsx | 16 --- docs-ui/src/app/{(docs) => }/about/page.mdx | 0 .../src/app/{(docs) => }/changelog/page.mdx | 0 .../{(docs) => }/components/[slug]/page.tsx | 0 docs-ui/src/app/layout.module.css | 6 + docs-ui/src/app/layout.tsx | 4 +- docs-ui/src/app/{(docs) => }/page.mdx | 0 .../{(docs) => }/theme/iconography/page.mdx | 0 .../app/{(docs) => }/theme/layout/page.mdx | 0 .../{(docs) => }/theme/responsive/page.mdx | 0 .../app/{(docs) => }/theme/theming/page.mdx | 0 .../{(docs) => }/theme/typography/page.mdx | 0 docs-ui/src/components/Theming/index.tsx | 32 ++++- .../ui/src/components/Menu/Menu.stories.tsx | 136 +++++++++--------- 15 files changed, 106 insertions(+), 93 deletions(-) delete mode 100644 docs-ui/src/app/(docs)/layout.module.css delete mode 100644 docs-ui/src/app/(docs)/layout.tsx rename docs-ui/src/app/{(docs) => }/about/page.mdx (100%) rename docs-ui/src/app/{(docs) => }/changelog/page.mdx (100%) rename docs-ui/src/app/{(docs) => }/components/[slug]/page.tsx (100%) rename docs-ui/src/app/{(docs) => }/page.mdx (100%) rename docs-ui/src/app/{(docs) => }/theme/iconography/page.mdx (100%) rename docs-ui/src/app/{(docs) => }/theme/layout/page.mdx (100%) rename docs-ui/src/app/{(docs) => }/theme/responsive/page.mdx (100%) rename docs-ui/src/app/{(docs) => }/theme/theming/page.mdx (100%) rename docs-ui/src/app/{(docs) => }/theme/typography/page.mdx (100%) diff --git a/docs-ui/src/app/(docs)/layout.module.css b/docs-ui/src/app/(docs)/layout.module.css deleted file mode 100644 index a4ea17aaac..0000000000 --- a/docs-ui/src/app/(docs)/layout.module.css +++ /dev/null @@ -1,5 +0,0 @@ -.pageContainer { - width: 100%; - max-width: 960px; - margin: 0 auto; -} diff --git a/docs-ui/src/app/(docs)/layout.tsx b/docs-ui/src/app/(docs)/layout.tsx deleted file mode 100644 index e136fd64f2..0000000000 --- a/docs-ui/src/app/(docs)/layout.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import type { Metadata } from 'next'; - -import styles from './layout.module.css'; - -export const metadata: Metadata = { - title: 'Backstage UI', - description: 'UI library for Backstage', -}; - -export default function DocsLayout({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { - return
{children}
; -} diff --git a/docs-ui/src/app/(docs)/about/page.mdx b/docs-ui/src/app/about/page.mdx similarity index 100% rename from docs-ui/src/app/(docs)/about/page.mdx rename to docs-ui/src/app/about/page.mdx diff --git a/docs-ui/src/app/(docs)/changelog/page.mdx b/docs-ui/src/app/changelog/page.mdx similarity index 100% rename from docs-ui/src/app/(docs)/changelog/page.mdx rename to docs-ui/src/app/changelog/page.mdx diff --git a/docs-ui/src/app/(docs)/components/[slug]/page.tsx b/docs-ui/src/app/components/[slug]/page.tsx similarity index 100% rename from docs-ui/src/app/(docs)/components/[slug]/page.tsx rename to docs-ui/src/app/components/[slug]/page.tsx diff --git a/docs-ui/src/app/layout.module.css b/docs-ui/src/app/layout.module.css index e7d9281c38..7399fc2485 100644 --- a/docs-ui/src/app/layout.module.css +++ b/docs-ui/src/app/layout.module.css @@ -13,6 +13,12 @@ border-radius: 0.5rem; } +.content { + width: 100%; + max-width: 960px; + margin: 0 auto; +} + @media (min-width: 768px) { .container { width: calc(100% - 332px - 40px); diff --git a/docs-ui/src/app/layout.tsx b/docs-ui/src/app/layout.tsx index 697f990587..58decbf22b 100644 --- a/docs-ui/src/app/layout.tsx +++ b/docs-ui/src/app/layout.tsx @@ -51,7 +51,9 @@ export default async function RootLayout({ -
{children}
+
+
{children}
+
diff --git a/docs-ui/src/app/(docs)/page.mdx b/docs-ui/src/app/page.mdx similarity index 100% rename from docs-ui/src/app/(docs)/page.mdx rename to docs-ui/src/app/page.mdx diff --git a/docs-ui/src/app/(docs)/theme/iconography/page.mdx b/docs-ui/src/app/theme/iconography/page.mdx similarity index 100% rename from docs-ui/src/app/(docs)/theme/iconography/page.mdx rename to docs-ui/src/app/theme/iconography/page.mdx diff --git a/docs-ui/src/app/(docs)/theme/layout/page.mdx b/docs-ui/src/app/theme/layout/page.mdx similarity index 100% rename from docs-ui/src/app/(docs)/theme/layout/page.mdx rename to docs-ui/src/app/theme/layout/page.mdx diff --git a/docs-ui/src/app/(docs)/theme/responsive/page.mdx b/docs-ui/src/app/theme/responsive/page.mdx similarity index 100% rename from docs-ui/src/app/(docs)/theme/responsive/page.mdx rename to docs-ui/src/app/theme/responsive/page.mdx diff --git a/docs-ui/src/app/(docs)/theme/theming/page.mdx b/docs-ui/src/app/theme/theming/page.mdx similarity index 100% rename from docs-ui/src/app/(docs)/theme/theming/page.mdx rename to docs-ui/src/app/theme/theming/page.mdx diff --git a/docs-ui/src/app/(docs)/theme/typography/page.mdx b/docs-ui/src/app/theme/typography/page.mdx similarity index 100% rename from docs-ui/src/app/(docs)/theme/typography/page.mdx rename to docs-ui/src/app/theme/typography/page.mdx diff --git a/docs-ui/src/components/Theming/index.tsx b/docs-ui/src/components/Theming/index.tsx index f015804756..fb669253a2 100644 --- a/docs-ui/src/components/Theming/index.tsx +++ b/docs-ui/src/components/Theming/index.tsx @@ -2,6 +2,7 @@ import { MDXRemote } from 'next-mdx-remote-client/rsc'; import { formattedMDXComponents } from '@/mdx-components'; import { Component } from '@/utils/changelog'; import { componentDefinitions } from '../../../../packages/ui/src/utils/componentDefinitions'; +import type { DataAttributeValues } from '../../../../packages/ui/src/types'; export function Theming({ component }: { component: Component }) { const componentDefinition = componentDefinitions[component]; @@ -11,15 +12,40 @@ export function Theming({ component }: { component: Component }) { } const classNames = componentDefinition.classNames; + const dataAttributes = componentDefinition.dataAttributes; - // Convert classNames object values to array - const classNameArray = Object.values(classNames); + // Get the first class name + const firstClassName = Object.values(classNames)[0]; + + // Create array of selectors combining first class name with data attributes + const selectorArray: string[] = []; + + if (dataAttributes) { + Object.entries(dataAttributes).forEach( + ([attributeName, attributeValues]) => { + (attributeValues as DataAttributeValues).forEach(value => { + selectorArray.push( + `${firstClassName}[data-${attributeName}="${value}"]`, + ); + }); + }, + ); + } + + const classNamesArray = [ + `${firstClassName}`, + ...selectorArray, + ...Object.values(classNames).slice(1), + ]; return ( `- \`${className}\``).join('\n')} + + Our theming system is based on a mix between CSS classes, CSS variables and data attributes. If you want to customise this component, you can use one of these class names below. + + ${classNamesArray.map(selector => `- \`${selector}\``).join('\n')} `} /> ); diff --git a/packages/ui/src/components/Menu/Menu.stories.tsx b/packages/ui/src/components/Menu/Menu.stories.tsx index 578ce945ae..c135b6f3f9 100644 --- a/packages/ui/src/components/Menu/Menu.stories.tsx +++ b/packages/ui/src/components/Menu/Menu.stories.tsx @@ -40,34 +40,33 @@ const options = [ ]; export const Default: Story = { - args: { - children: ( - <> - ( - - )} - /> - - - - Settings - Invite new members - Download app - Log out - - - - - ), - }, + args: { children: undefined }, + render: args => ( + + ( + + )} + /> + + + + Settings + Invite new members + Download app + Log out + + + + + ), }; export const Open: Story = { @@ -75,6 +74,7 @@ export const Open: Story = { ...Default.args, open: true, }, + render: Default.render, }; export const OpenOnHover: Story = { @@ -82,49 +82,49 @@ export const OpenOnHover: Story = { ...Default.args, openOnHover: true, }, + render: Default.render, }; export const Submenu: Story = { - args: { - children: ( - <> - ( - - )} - /> - - - - Settings - Invite new members - Download app - Log out - - Submenu - - - - Submenu Item 1 - Submenu Item 2 - Submenu Item 3 - - - - - - - - - ), - }, + args: { children: undefined }, + render: args => ( + + ( + + )} + /> + + + + Settings + Invite new members + Download app + Log out + + Submenu + + + + Submenu Item 1 + Submenu Item 2 + Submenu Item 3 + + + + + + + + + ), }; export const SubmenuCombobox = () => {