首页
/ Backstage 主题定制完全指南:基于 @backstage/theme 打造专属外观(旧前端系统)

Backstage 主题定制完全指南:基于 @backstage/theme 打造专属外观(旧前端系统)

2026-09-10 23:49:09作者:齐冠琰

本篇技术指南面向仍在使用旧前端系统(Old Frontend System,即通过 @backstage/app-defaultscreateApp 组合应用)的 Backstage 应用,系统讲解如何利用官方 @backstage/theme 包定制应用主题外观:从创建自定义主题、注册到应用,到精细化的排版、字体、组件样式覆盖、Logo、图标、侧边栏子菜单定制。读完本文,你将能独立完成一套从配色、字体到图标、Logo 的完整 Backstage 品牌化改造。若你的应用已迁移到新前端系统,请阅读 新版指南

主题系统概览:@backstage/theme

Backstage 内置了一套默认主题,包含浅色(light)与深色(dark)两种模式变体。这套主题由 @backstage/theme 包提供,该包还导出了大量用于定制默认主题、或从零创建全新主题的工具函数。

从仓库源码看,@backstage/theme 的核心导出集中在 packages/theme/src/index.ts,它重新导出了 unifiedbasev4v5 四个子模块,其中:

  • unifiedcreateUnifiedThemeUnifiedThemeProviderthemes(内置 light/dark)、createUnifiedThemeFromV4 等统一主题(Unified Theme)相关 API;
  • basecreateBaseThemeOptionspalettespageThemeshapesgenPageThemedefaultTypographycolorVariants 等基础构造工具与类型;
  • v4 / v5:分别面向 Material UI v4 与 v5 的主题适配层。

其中值得特别说明的是 Unified Theme(统一主题) 机制:createUnifiedTheme 会同时生成 Material UI v4 与 v5 两套主题对象(见 UnifiedTheme.tsx),并通过 UnifiedThemeProvider 同时为 @material-ui/*(v4)和 @mui/*(v5)组件注入对应主题,这正是 Backstage 在过渡期能同时兼容两代 Material UI 的关键。

创建自定义主题:createUnifiedTheme 起步

创建新主题最简单的方式是使用 @backstage/theme 导出的 createUnifiedTheme 函数,用它覆盖默认主题的基础参数,如调色板(color palette)与字体(font)。

例如,基于默认浅色主题创建一个新主题:

import {
  createBaseThemeOptions,
  createUnifiedTheme,
  palettes,
} from '@backstage/theme';

export const myTheme = createUnifiedTheme({
  ...createBaseThemeOptions({
    palette: palettes.light,
  }),
  fontFamily: 'Comic Sans MS',
  defaultPageTheme: 'home',
});

建议:在 packages/app/src 下创建 theme 文件夹来存放主题文件,让项目结构更整洁。

createUnifiedTheme 接收一个 UnifiedThemeOptions 对象(定义见 UnifiedTheme.tsx),内部先调用 createBaseThemeOptions 生成基础配置,再合并默认组件主题与你的 components 覆盖项,最终同时产出 v4、v5 两套 Material UI 主题。

createBaseThemeOptions 的默认值

理解 createBaseThemeOptions 的默认行为有助于掌握主题覆盖的边界。查看其源码 createBaseThemeOptions.ts

  • htmlFontSize 默认 16
  • fontFamily 默认 '"Helvetica Neue", Helvetica, Roboto, Arial, sans-serif'
  • defaultPageTheme 默认 home,且必须在 pageTheme 中存在,否则会抛出 X is not defined in pageTheme. 错误;
  • pageTheme 默认使用内置的全套页面主题;
  • 返回对象中包含 page(当前默认页主题)与 getPageTheme({ themeId })(按主题 ID 取页面主题,未命中时回退到默认页主题)两个 Backstage 扩展字段。

内置调色板 palettes

palettes.lightpalettes.dark 定义了 Backstage 的全部基础色板,见 palettes.ts。除了 Material UI 标准的 primarysecondarybackground 等,还包含大量 Backstage 扩展配色,覆盖以下类别:

  • statusokwarningerrorrunningpendingaborted 六种状态色;
  • banner:横幅的 infoerrortextlinkcloseButtonColorwarning
  • 文本与背景类:textContrasttextVerySubtletextSubtlehighlighterrorBackgroundwarningBackgroundinfoBackgrounderrorTextinfoTextwarningTextlinklinkHovergoldborder
  • navigation:侧边导航的 backgroundindicatorcolorselectedColor,以及可选的 navItem.hoverBackgroundsubmenu.background
  • tabbarindicator
  • pinSidebarButtoniconbackground
  • bursts(已标记 deprecated,未来版本会移除):fontColorslackChannelTextbackgroundColorgradient

如果你不需要基于默认主题微调,也可以从零构建一个符合 BackstageTheme 类型的主题——@backstage/theme 导出了完整的类型定义,关于从零构建可参考 Material UI 的 theming 文档。

将自定义主题接入应用(旧前端系统)

旧前端系统中,自定义主题通过 createAppthemes 配置项传入。接入上文创建的主题:

import { createApp } from '@backstage/app-defaults';
import { ThemeProvider } from '@material-ui/core/styles';
import CssBaseline from '@material-ui/core/CssBaseline';
import LightIcon from '@material-ui/icons/WbSunny';
import { UnifiedThemeProvider} from '@backstage/theme';
import { myTheme } from './themes/myTheme';

const app = createApp({
  apis: ...,
  plugins: ...,
  themes: [{
    id: 'my-theme',
    title: 'My Custom Theme',
    variant: 'light',
    icon: <LightIcon />,
    Provider: ({ children }) => (
      <UnifiedThemeProvider theme={myTheme} children={children} />
    ),
  }]
})

每个主题项包含四个关键字段:

字段 说明
id 主题唯一标识,用于切换与存储用户选择
title 在主题切换菜单中展示的名称
variant lightdark,决定主题模式
icon 主题切换菜单中显示的图标组件
Provider 包裹应用子树的主题 Provider,这里使用 UnifiedThemeProvider 注入 Unified Theme

需要留意:你传入的自定义主题列表会覆盖默认主题。如果仍想保留默认的浅色/深色主题,可以直接从 @backstage/theme 导入它们——仓库中默认主题定义于 themes.ts

import { themes } from '@backstage/theme';

// themes.light / themes.dark
export const themes = {
  light: createUnifiedTheme({ palette: palettes.light }),
  dark: createUnifiedTheme({ palette: palettes.dark }),
};

UnifiedThemeProvider 的工作原理

UnifiedThemeProvider(见 UnifiedThemeProvider.tsx)会从 Unified Theme 中分别取出 v4 与 v5 主题,并同时挂载:

  • 对 v4:StylesProvider(使用 jss4- 生产前缀避免与 v5 样式冲突)+ ThemeProvider
  • 对 v5:StyledEngineProvider injectFirst + MUI v5 的 ThemeProvider

同时它还通过 useApplyThemeAttributes(见 useApplyThemeAttributes.ts)在 <body> 上维护 data-theme-modedata-theme-namedata-unified-theme-stack 三个属性,供全局 CSS 按主题模式/名称编写样式,这在多主题嵌套场景中尤其有用。

完整自定义主题示例:配色与页面主题

下面是一个更完整的示例,覆盖调色板全面定制与各页面头部(Header)的渐变与图形:

import {
  createBaseThemeOptions,
  createUnifiedTheme,
  genPageTheme,
  palettes,
  shapes,
} from '@backstage/theme';

export const myTheme = createUnifiedTheme({
  ...createBaseThemeOptions({
    palette: {
      ...palettes.light,
      primary: {
        main: '#343b58',
      },
      secondary: {
        main: '#565a6e',
      },
      error: {
        main: '#8c4351',
      },
      warning: {
        main: '#8f5e15',
      },
      info: {
        main: '#34548a',
      },
      success: {
        main: '#485e30',
      },
      background: {
        default: '#d5d6db',
        paper: '#d5d6db',
      },
      banner: {
        info: '#34548a',
        error: '#8c4351',
        text: '#343b58',
        link: '#565a6e',
      },
      errorBackground: '#8c4351',
      warningBackground: '#8f5e15',
      infoBackground: '#343b58',
      navigation: {
        background: '#343b58',
        indicator: '#8f5e15',
        color: '#d5d6db',
        selectedColor: '#ffffff',
      },
    },
  }),
  defaultPageTheme: 'home',
  fontFamily: 'Comic Sans MS',
  /* below drives the header colors */
  pageTheme: {
    home: genPageTheme({ colors: ['#8c4351', '#343b58'], shape: shapes.wave }),
    documentation: genPageTheme({
      colors: ['#8c4351', '#343b58'],
      shape: shapes.wave2,
    }),
    tool: genPageTheme({ colors: ['#8c4351', '#343b58'], shape: shapes.round }),
    service: genPageTheme({
      colors: ['#8c4351', '#343b58'],
      shape: shapes.wave,
    }),
    website: genPageTheme({
      colors: ['#8c4351', '#343b58'],
      shape: shapes.wave,
    }),
    library: genPageTheme({
      colors: ['#8c4351', '#343b58'],
      shape: shapes.wave,
    }),
    other: genPageTheme({ colors: ['#8c4351', '#343b58'], shape: shapes.wave }),
    app: genPageTheme({ colors: ['#8c4351', '#343b58'], shape: shapes.wave }),
    apis: genPageTheme({ colors: ['#8c4351', '#343b58'], shape: shapes.wave }),
  },
});

genPageThemeshapescolorVariants 源码解读

pageTheme 对应各页面类型(homedocumentationtoolservicewebsitelibraryotherappapiscard)的头部背景。相关实现位于 pageTheme.ts

  • genPageTheme({ colors, shape, options }) 生成一个 PageTheme:当 colors 只有一个值时自动复制为两个,拼出 linear-gradient(90deg, ...),再与 shape(SVG data URI 背景图)合并成最终 backgroundImage;默认 fontColor#FFFFFF
  • shapes 内置 wavewave2roundsquare 四种装饰形状(均为白色透明遮罩的 SVG data URI);
  • colorVariants 内置 darkGreymarineBlueveryBluerubyRedtoastyOrangepurpleSkyeveningSeatealpinkSeagreens 等预设渐变色组合,例如 teal: ['#005B4B']pinkSea: ['#C8077A', '#C2297D']

内置 pageTheme 使用的组合如:home 使用 teal + wavedocumentation 使用 pinkSea + wave2tool 使用 purpleSky + round,可作为自定义时的参照。

更完整的、包含 Backstage 与 Material UI 组件覆盖(overrides)的主题示例,可参考官方 demo 站点应用的 Aperture 主题实现。

自定义排版(Typography)

创建自定义主题时,可以定制默认排版的各个方面。下面是一个基于简化主题的完整排版示例:

import {
  createBaseThemeOptions,
  createUnifiedTheme,
  palettes,
} from '@backstage/theme';

export const myTheme = createUnifiedTheme({
  ...createBaseThemeOptions({
    palette: palettes.light,
    typography: {
      htmlFontSize: 16,
      fontFamily: 'Arial, sans-serif',
      h1: {
        fontSize: 54,
        fontWeight: 700,
        marginBottom: 10,
      },
      h2: {
        fontSize: 40,
        fontWeight: 700,
        marginBottom: 8,
      },
      h3: {
        fontSize: 32,
        fontWeight: 700,
        marginBottom: 6,
      },
      h4: {
        fontWeight: 700,
        fontSize: 28,
        marginBottom: 6,
      },
      h5: {
        fontWeight: 700,
        fontSize: 24,
        marginBottom: 4,
      },
      h6: {
        fontWeight: 700,
        fontSize: 20,
        marginBottom: 2,
      },
    },
    defaultPageTheme: 'home',
  }),
});

BackstageTypography 类型(见 base/types.ts)要求 htmlFontSizefontFamily 以及 h1–h6 各级标题的 fontSizefontWeightmarginBottom 字段,各级标题还支持可选的 fontFamily 覆盖。

只覆盖部分排版设置

若只想覆盖排版中的一部分(例如只改 h1),需要基于 defaultTypography 展开,避免丢失其余标题样式。仓库中 defaultTypography 定义于 createBaseThemeOptions.ts,完整包含 htmlFontSize 与 h1–h6 的默认值:

import {
  createBaseThemeOptions,
  createUnifiedTheme,
  defaultTypography,
  palettes,
} from '@backstage/theme';

export const myTheme = createUnifiedTheme({
  ...createBaseThemeOptions({
    palette: palettes.light,
    typography: {
      ...defaultTypography,
      htmlFontSize: 16,
      fontFamily: 'Roboto, sans-serif',
      h1: {
        fontSize: 72,
        fontWeight: 700,
        marginBottom: 10,
      },
    },
    defaultPageTheme: 'home',
  }),
});

注意 defaultTypography 是一个会被 createBaseThemeOptions 内部就地修改的共享对象(htmlFontSizefontFamily 会被默认值直接赋值),因此推荐始终以展开(spread)方式使用它,以保证各个主题之间互不影响。

自定义字体(Custom Fonts)

添加自定义字体分三步:存放字体文件、声明 @font-face、通过 MuiCssBaselinestyleOverrides 挂载。

  1. 存放字体:建议在前端应用 src 下创建 assets/fonts 目录,将字体文件(如 .woff2)放入其中;
  2. 声明字体:按 Material UI Typography 的 @font-face 语法声明字体样式;
  3. 挂载字体:在主题的 components.MuiCssBaseline.styleOverrides 中,把字体定义加入 '@font-face' 数组。
import MyCustomFont from '../assets/fonts/My-Custom-Font.woff2';

const myCustomFont = {
  fontFamily: 'My-Custom-Font',
  fontStyle: 'normal',
  fontDisplay: 'swap',
  fontWeight: 300,
  src: `
    local('My-Custom-Font'),
    url(${MyCustomFont}) format('woff2'),
  `,
};

export const myTheme = createUnifiedTheme({
  fontFamily: 'My-Custom-Font',
  palette: palettes.light,
  components: {
    MuiCssBaseline: {
      styleOverrides: {
        '@font-face': [myCustomFont],
      },
    },
  },
});

同时使用多种字体

如果想为正文与标题分别使用不同字体:将顶层 fontFamily 设为正文所需字体,再在 typography 中为各级标题覆盖 fontFamily

import MyCustomFont from '../assets/fonts/My-Custom-Font.woff2';
import myAwesomeFont from '../assets/fonts/My-Awesome-Font.woff2';

const myCustomFont = {
  fontFamily: 'My-Custom-Font',
  fontStyle: 'normal',
  fontDisplay: 'swap',
  fontWeight: 300,
  src: `
    local('My-Custom-Font'),
    url(${MyCustomFont}) format('woff2'),
  `,
};

const myAwesomeFont = {
  fontFamily: 'My-Awesome-Font',
  fontStyle: 'normal',
  fontDisplay: 'swap',
  fontWeight: 300,
  src: `
    local('My-Awesome-Font'),
    url(${myAwesomeFont}) format('woff2'),
  `,
};

export const myTheme = createUnifiedTheme({
  fontFamily: 'My-Custom-Font',
  components: {
    MuiCssBaseline: {
      styleOverrides: {
        '@font-face': [myCustomFont, myAwesomeFont],
      },
    },
  },
  ...createBaseThemeOptions({
    palette: palettes.light,
    typography: {
      ...defaultTypography,
      htmlFontSize: 16,
      fontFamily: 'My-Custom-Font',
      h1: {
        fontSize: 72,
        fontWeight: 700,
        marginBottom: 10,
        fontFamily: 'My-Awesome-Font',
      },
    },
    defaultPageTheme: 'home',
  }),
});

覆盖 Backstage 与 Material UI 组件样式

自定义主题本质上是为组件 CSS 规则提供取值来源。以 Backstage 某个组件为例,它的样式可能是这样写的:

const useStyles = makeStyles<BackstageTheme>(
  theme => ({
    header: {
      padding: theme.spacing(3),
      boxShadow: '0 0 8px 3px rgba(20, 20, 20, 0.3)',
      backgroundImage: theme.page.backgroundImage,
    },
  }),
  { name: 'BackstageHeader' },
);

关键点在于:padding 取自 theme.spacingbackgroundImage 取自 theme.page.backgroundImage,因此调整主题中的 spacing 或页面主题就能直接作用于这些属性;但 boxShadow 是硬编码的,没有引用任何主题值——仅靠自定义主题无法改变 box-shadow,也无法添加组件原本没有定义的 CSS 规则(如 margin)。这类情况必须通过 overrides(样式覆盖) 处理:

import {
  createBaseThemeOptions,
  createUnifiedTheme,
  palettes,
} from '@backstage/theme';

export const myTheme = createUnifiedTheme({
  ...createBaseThemeOptions({
    palette: palettes.light,
  }),
  fontFamily: 'Comic Sans MS',
  defaultPageTheme: 'home',
  components: {
    BackstageHeader: {
      styleOverrides: {
        header: ({ theme }) => ({
          width: 'auto',
          margin: '20px',
          boxShadow: 'none',
          borderBottom: `4px solid ${theme.palette.primary.main}`,
        }),
      },
    },
  },
});

components 配置会与仓库内置的 defaultComponentThemes(见 v5/defaultComponentThemes.ts)合并,随后同时生成 v4 与 v5 的组件覆盖——这正是 createUnifiedThemeconst components = { ...defaultComponentThemes, ...options.components } 所做的事(见 UnifiedTheme.tsx)。

自定义 Logo

除了主题,你还可以定制站点左上角的 Logo。在旧前端系统中,找到应用内的 src/components/Root/ 目录,其中有两个组件:

  • LogoFull.tsx —— 侧边栏展开时使用的大 Logo;
  • LogoIcon.tsx —— 侧边栏收起时使用的小 Logo。

替换方式有两种:

方式一:直接替换 SVG 定义。将上述组件中的相关代码替换为你的原始 SVG 定义。

方式二:导入位图(如 PNG)。将新图片放入子目录,例如 src/components/Root/logo/my-company-logo.png,然后:

import MyCustomLogoFull from './logo/my-company-logo.png';

const LogoFull = () => {
  return <img src={MyCustomLogoFull} />;
};

图标定制

前面已经了解了主题与 Logo 的定制,接下来看如何覆盖现有图标、以及如何新增图标。

覆盖默认图标(Custom Icons)

你可以定制应用的默认图标。可覆盖的默认图标集合定义在 packages/app-defaults/src/defaults/icons.tsx,包括 catalogscaffoldertechdocssearchgithubgroupuserwarningstarunstarredexternalLink,以及 kind:apikind:componentkind:domainkind:groupkind:locationkind:systemkind:userkind:resourcekind:template 等目录实体类型图标。

要求:图标文件需为 .svg 格式,并为其创建 React 组件。

第一步:创建 React 组件。在前端应用 src 下建议创建 assets/icons 目录及 CustomIcons.tsx 文件:

import { SvgIcon, SvgIconProps } from '@material-ui/core';

export const ExampleIcon = (props: SvgIconProps) => (
  <SvgIcon {...props} viewBox="0 0 24 24">
    <path
      fill="currentColor"
      width="1em"
      height="1em"
      display="inline-block"
      d="M11.6335 10.8398C11.6335 11.6563 12.065 12.9922 13.0863 12.9922C14.1075 12.9922 14.539 11.6563 14.539 10.8398C14.539 10.0234 14.1075 8.6875 13.0863 8.6875C12.065 8.6875 11.6335 10.0234 11.6335 10.8398V10.8398ZM2.38419e-07 8.86719C2.38419e-07 10.1133 0.126667 11.4336 0.692709 12.5781C2.19292 15.5703 6.3175 15.5 9.27042 15.5C12.2708 15.5 16.6408 15.6055 18.2004 12.5781C18.7783 11.4453 19 10.1133 19 8.86719C19 7.23047 18.4498 5.68359 17.3573 4.42969C17.5631 3.8125 17.6621 3.16406 17.6621 2.52344C17.6621 1.68359 17.4681 1.26172 17.0842 0.5C15.291 0.5 14.1431 0.851562 12.7775 1.90625C11.6296 1.63672 10.45 1.51562 9.26646 1.51562C8.19771 1.51562 7.12104 1.62891 6.08396 1.875C4.73813 0.832031 3.59021 0.5 1.81687 0.5C1.42896 1.26172 1.23896 1.68359 1.23896 2.52344C1.23896 3.16406 1.34188 3.80078 1.54375 4.40625C0.455209 5.67188 2.38419e-07 7.23047 2.38419e-07 8.86719V8.86719ZM2.54521 10.8398C2.54521 9.125 3.60208 7.61328 5.45458 7.61328C6.20271 7.61328 6.91917 7.74609 7.67125 7.84766C8.26104 7.9375 8.85083 7.97266 9.45646 7.97266C10.0581 7.97266 10.6479 7.9375 11.2417 7.84766C11.9819 7.74609 12.7063 7.61328 13.4583 7.61328C15.3108 7.61328 16.3677 9.125 16.3677 10.8398C16.3677 14.2695 13.1852 14.7969 10.4144 14.7969H8.50646C5.72375 14.7969 2.54521 14.2734 2.54521 10.8398V10.8398ZM5.81479 8.6875C6.83604 8.6875 7.2675 10.0234 7.2675 10.8398C7.2675 11.6563 6.83604 12.9922 5.81479 12.9922C4.79354 12.9922 4.36208 11.6563 4.36208 10.8398C4.36208 10.0234 4.79354 8.6875 5.81479 8.6875Z"
    />
  </SvgIcon>
);

第二步:在 App.tsx 中挂载自定义图标

/* highlight-add-next-line */
import { ExampleIcon } from './assets/customIcons'


const app = createApp({
  apis,
  components: {
    {/* ... */}
  },
  themes: [
    {/* ... */}
  ],
  /* highlight-add-start */
  icons: {
    github: ExampleIcon,
  },
  /* highlight-add-end */
  bindRoutes({ bind }) {
    {/* ... */}
  }
})

新增图标(Adding Icons)

如果默认图标无法满足需求,可以注册更多图标,用于实体(Entity)Links 等场景。以 Material UI 的 AlarmIcon 为例:

  1. 打开 packages/app/src 下的 App.tsx
  2. 在其余 import 中追加:import AlarmIcon from '@material-ui/icons/Alarm';
  3. createApp 中加入:
const app = createApp({
  apis: ...,
  plugins: ...,
  /* highlight-add-start */
  icons: {
    alert: AlarmIcon,
  },
/* highlight-add-end */
  themes: ...,
  components: ...,
});
  1. 现在可以在实体 Links 中通过 icon: alert 引用它:
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: artist-lookup
  description: Artist Lookup
  links:
    - url: https://example.com/alert
      title: Alerts
      icon: alert

实际效果如下:

在实体链接中使用自定义 alert 图标的效果示例

另一种使用方式是通过 AppContext 获取图标,适合需要在多处复用的场景:

import { useApp } from '@backstage/core-plugin-api';

const app = useApp();
const alertIcon = app.getSystemIcon('alert');

注意:如果请求的图标既不在默认图标中、也未注册,系统会回退到 Material UI 的 LanguageIcon

自定义侧边栏:子菜单(Sidebar Sub-menu)

除了主题,Backstage 还提供了大量外观定制能力,侧边栏就是其中之一。下面演示如何为侧边栏添加子菜单。

  1. 打开 packages/app/src/components/Root 下的 Root.tsx(侧边栏代码所在文件);
  2. 添加 useApp 导入:
import { useApp } from '@backstage/core-plugin-api';
  1. 更新 @backstage/core-components 导入,加入子菜单相关组件:
import {
  Sidebar,
  sidebarConfig,
  SidebarDivider,
  SidebarGroup,
  SidebarItem,
  SidebarPage,
  SidebarScrollWrapper,
  SidebarSpace,
  useSidebarOpenState,
  Link,
  /* highlight-add-start */
  GroupIcon,
  SidebarSubmenu,
  SidebarSubmenuItem,
  /* highlight-add-end */
} from '@backstage/core-components';
  1. <SidebarItem icon={HomeIcon} to="catalog" text="Home" /> 替换为带子菜单的版本:
<SidebarItem icon={HomeIcon} to="catalog" text="Home">
  <SidebarSubmenu title="Catalog">
    <SidebarSubmenuItem
      title="Domains"
      to="catalog?filters[kind]=domain"
      icon={useApp().getSystemIcon('kind:domain')}
    />
    <SidebarSubmenuItem
      title="Systems"
      to="catalog?filters[kind]=system"
      icon={useApp().getSystemIcon('kind:system')}
    />
    <SidebarSubmenuItem
      title="Components"
      to="catalog?filters[kind]=component"
      icon={useApp().getSystemIcon('kind:component')}
    />
    <SidebarSubmenuItem
      title="APIs"
      to="catalog?filters[kind]=api"
      icon={useApp().getSystemIcon('kind:api')}
    />
    <SidebarDivider />
    <SidebarSubmenuItem
      title="Resources"
      to="catalog?filters[kind]=resource"
      icon={useApp().getSystemIcon('kind:resource')}
    />
    <SidebarDivider />
    <SidebarSubmenuItem
      title="Groups"
      to="catalog?filters[kind]=group"
      icon={useApp().getSystemIcon('kind:group')}
    />
    <SidebarSubmenuItem
      title="Users"
      to="catalog?filters[kind]=user"
      icon={useApp().getSystemIcon('kind:user')}
    />
  </SidebarSubmenu>
</SidebarItem>

启动 Backstage 后,将鼠标悬停在侧边栏的 Home 选项上,即可看到带各类目(Kinds)链接的子菜单,效果如下:

侧边栏子菜单示例:悬停 Home 显示的目录类目子菜单

这里子菜单项直接通过 useApp().getSystemIcon('kind:domain') 等调用复用了前面“图标定制”中讲解的系统图标能力——默认图标定义即包含全部 kind:* 实体类目图标。

自定义首页(Homepage)

除了自定义主题与 Logo,你还可以定制应用首页。完整的首页定制指南请参见 首页定制指南

迁移到 Material UI v5

Backstage 现已支持 Material UI v5。如果你需要将现有应用升级到 MUI v5,可参考 迁移指南 开始操作。而 @backstage/theme 的 Unified Theme 机制(createUnifiedTheme 同时生成 v4/v5 两套主题、UnifiedThemeProvider 同时注入两套 Provider)正是这一迁移过程中保证新旧组件样式一致性的基础设施。

小结

至此,你已经掌握了旧前端系统下 Backstage 外观定制的完整链路:

  • createUnifiedTheme + createBaseThemeOptions 创建主题,覆盖调色板、字体、页面主题(genPageTheme + shapes);
  • 通过 createAppthemes 配置将主题接入应用,并理解 UnifiedThemeProvider 同时服务 v4/v5 的机制;
  • defaultTypography 局部覆盖排版,用 MuiCssBaselinestyleOverrides 挂载 @font-face 自定义字体;
  • 对未引用主题值的组件样式使用 components.styleOverrides 覆盖;
  • 替换 LogoFull/LogoIcon 定制 Logo,通过 icons 配置覆盖或新增系统图标并在实体 Links 与 useApp().getSystemIcon 中使用;
  • SidebarSubmenu / SidebarSubmenuItem 扩展侧边栏子菜单。

以上所有定制均以 @backstage/theme 包(packages/theme)与各应用示例文件(packages/app)为事实依据,可直接对照仓库源码逐步验证与实践。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.15 K
2.78 K
kernelkernel
deepin linux kernel
C
34
18
docsdocs
暂无描述
Markdown
904
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
931
1.86 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
862
1.36 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.95 K
1.03 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.38 K
1.47 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
535
605
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
549
398
leetcodeleetcode
🔥LeetCode solutions in any programming language | 多种编程语言实现 LeetCode、《剑指 Offer(第 2 版)》、《程序员面试金典(第 6 版)》题解
Markdown
77
23