From a863540fd4130062edad31b17a343d9fbef70bd0 Mon Sep 17 00:00:00 2001 From: Johnny Huynh <27847622+johnnyhuy@users.noreply.github.com> Date: Sat, 27 Dec 2025 23:05:44 +1100 Subject: [PATCH 1/6] feat: Implement Primer integration with theming support and demo components --- AGENTS.md | 101 ++++++++++ packages/app/README-theme.md | 43 +++++ packages/app/package.json | 3 +- packages/app/src/App.tsx | 25 +++ packages/app/src/components/PrimerDemo.tsx | 41 +++++ .../app/src/components/PrimerDemoPage.tsx | 18 ++ packages/app/src/index.tsx | 1 + packages/app/src/styles/brand.css | 25 +++ packages/app/src/themes/brandTheme.ts | 64 +++++++ yarn.lock | 173 ++++++++++++++++++ 10 files changed, 493 insertions(+), 1 deletion(-) create mode 100644 AGENTS.md create mode 100644 packages/app/README-theme.md create mode 100644 packages/app/src/components/PrimerDemo.tsx create mode 100644 packages/app/src/components/PrimerDemoPage.tsx create mode 100644 packages/app/src/styles/brand.css create mode 100644 packages/app/src/themes/brandTheme.ts diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..9bfcf04 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,101 @@ +# AI Agent Instructions for Backstage Showcase + +## Project Overview + +This is a **Backstage developer portal** — a monorepo with a React frontend (`packages/app`) and Node.js backend (`packages/backend`), plus custom plugins in `plugins/`. It uses the new Backstage backend system with `createBackend()`. + +## Development Commands + +All commands go through **mise** (not yarn directly): + +```bash +mise run install # Install dependencies (runs yarn install) +mise run dev # Start frontend (localhost:3000) + backend (localhost:7007) +mise run lint # Lint and type-check +mise run test # Run tests +mise run build # Build Docker image +mise run up # Start with Traefik (production-like) +``` + +## Architecture + +### Monorepo Structure + +- **`packages/app`** — React frontend using MUI v5 + `@backstage/core-components` +- **`packages/backend`** — Node.js backend using `@backstage/backend-defaults` +- **`plugins/`** — Custom plugins (scoped as `@internal/`): + - `plausible/` — Analytics integration (frontend-plugin) + - `permission-backend-module-default/` — RBAC policy (backend-plugin-module) + +### Backend Plugin Registration + +Backend uses the new system. Add plugins in [packages/backend/src/index.ts](packages/backend/src/index.ts): + +```typescript +const backend = createBackend(); +backend.add(import('@backstage/plugin-catalog-backend')); +backend.add( + import('@internal/backstage-plugin-permission-backend-module-default'), +); +backend.start(); +``` + +### Frontend App Structure + +- Entry: [packages/app/src/App.tsx](packages/app/src/App.tsx) +- Routes use `FlatRoutes` with `` components +- Entity pages: [packages/app/src/components/catalog/EntityPage.tsx](packages/app/src/components/catalog/EntityPage.tsx) +- Sidebar navigation: [packages/app/src/components/Root/Root.tsx](packages/app/src/components/Root/Root.tsx) + +## Theming Pattern + +Custom themes use `createUnifiedTheme()` from `@backstage/theme`: + +- Default theme: [packages/app/src/theme/index.ts](packages/app/src/theme/index.ts) +- Brand themes: [packages/app/src/themes/brandTheme.ts](packages/app/src/themes/brandTheme.ts) + +Themes are registered in App.tsx via the `themes` array with `UnifiedThemeProvider`. + +## Configuration Files + +- `app-config.yaml` — Base config (local development) +- `app-config.local.yaml` — Local overrides (gitignored) +- `app-config.production.yaml` — Production config (uses env vars like `${APP_BASE_URL}`) + +Environment variables are loaded from `.env` via mise. + +## Permission System + +RBAC is implemented in [plugins/permission-backend-module-default/src/module.ts](plugins/permission-backend-module-default/src/module.ts): + +- Groups: `readers` (read-only), `developers` (CRUD), `admins` +- Uses `policyExtensionPoint` to register custom `PermissionPolicy` + +## Software Templates + +Templates live in `examples/templates/`. Each template has: + +- `template.yaml` — Scaffolder definition with parameters and steps +- `template/` — Skeleton files to copy + +Example: [examples/templates/github-blank-repo/template.yaml](examples/templates/github-blank-repo/template.yaml) + +## Entity Catalog + +- Sample entities: `examples/` directory (components, APIs, domains, systems) +- Entity types customized per kind in [EntityPage.tsx](packages/app/src/components/catalog/EntityPage.tsx) +- Uses `EntitySwitch.Case` with predicates like `isKind('component')` + +## Docker & Deployment + +- Multi-stage Dockerfile uses asdf for Node.js/Python +- Production runs: `node . --config ../../app-config.yaml --config ../../app-config.production.yaml` +- Traefik reverse proxy via `compose.yaml` + +## Key Conventions + +1. **Plugin naming**: `@internal/backstage-plugin-{name}` for private plugins +2. **Internal links**: Use `link:../app` in package.json for local dependencies +3. **MUI imports**: Use `@mui/material` (v5), not `@material-ui/core` (v4) +4. **Icons**: Import from `@mui/icons-material` as `IconComponent` for Sidebar +5. **Yarn workspaces**: `packages/*` and `plugins/*` diff --git a/packages/app/README-theme.md b/packages/app/README-theme.md new file mode 100644 index 0000000..a7bbdb3 --- /dev/null +++ b/packages/app/README-theme.md @@ -0,0 +1,43 @@ +# App theming (Brand + Primer) + +This app uses Backstage’s Unified Theming API (via `UnifiedThemeProvider` + `createUnifiedTheme`). + +## Switching themes + +- In the UI: open **User Settings** → **Appearance** → pick **Brand Light** or **Brand Dark**. +- If you don’t see the theme picker, ensure the app has more than one registered theme in the frontend. + +## Where theme tokens live + +- Brand themes: `packages/app/src/themes/brandTheme.ts` + - `brandLightTheme` + - `brandDarkTheme` +- Existing app theme: `packages/app/src/theme/index.ts` (`backstageTheme`) + +The brand themes are intentionally subtle and mostly reuse Backstage base palettes. + +## Backstage UI CSS variable overrides + +`packages/app/src/styles/brand.css` contains minimal overrides for Backstage UI CSS variables. + +- The overrides are scoped to: + - `[data-theme-mode='light']` + - `[data-theme-mode='dark']` +- No element resets are applied (to avoid breaking existing Backstage/MUI styling). +- The CSS is imported once from the app entrypoint. + +## Primer (GitHub design system) integration + +Primer is added for incremental, isolated usage. + +- Dependency: `@primer/react` +- Demo component: `packages/app/src/components/PrimerDemo.tsx` +- Demo page: `packages/app/src/components/PrimerDemoPage.tsx` mounted at `/primer-demo` + +How we avoid global styling conflicts: + +- We do **not** wrap the entire Backstage app in Primer providers. +- Primer `BaseStyles` is applied only inside the demo component subtree. +- The page itself still uses Backstage layout components (`Page`, `Header`, `Content`). + +If you see unexpected styling changes outside the demo page, it likely means Primer styles escaped scope (which should not happen with the current setup). diff --git a/packages/app/package.json b/packages/app/package.json index 059855d..f31f2ad 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -51,6 +51,7 @@ "@mui/styles": "^5.18.0", "@mui/utils": "^5.15.14", "@mui/x-charts": "^8.0.0", + "@primer/react": "^38.6.2", "history": "^5.0.0", "react": "^18.0.2", "react-dom": "^18.0.2", @@ -87,4 +88,4 @@ "files": [ "dist" ] -} +} \ No newline at end of file diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index 51ca1a8..2d4d4f1 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -45,6 +45,8 @@ import { HomePage } from './components/home/HomePage'; import CssBaseline from '@mui/material/CssBaseline'; import { PlausibleAnalytics } from '@internal/backstage-plugin-plausible'; import { githubAuthApiRef, gitlabAuthApiRef } from '@backstage/core-plugin-api'; +import { brandDarkTheme, brandLightTheme } from './themes/brandTheme'; +import { PrimerDemoPage } from './components/PrimerDemoPage'; const app = createApp({ apis, @@ -101,12 +103,35 @@ const app = createApp({ ), }, + { + id: 'brand-light', + title: 'Brand Light', + variant: 'light', + Provider: ({ children }) => ( + + + {children} + + ), + }, + { + id: 'brand-dark', + title: 'Brand Dark', + variant: 'dark', + Provider: ({ children }) => ( + + + {children} + + ), + }, ], }); const routes = ( } /> + } /> + +
+
+ + +
+

+ Primer BaseStyles + ThemeProvider are scoped to this card only. +

+
+
+ + ); +} diff --git a/packages/app/src/components/PrimerDemoPage.tsx b/packages/app/src/components/PrimerDemoPage.tsx new file mode 100644 index 0000000..0ffc371 --- /dev/null +++ b/packages/app/src/components/PrimerDemoPage.tsx @@ -0,0 +1,18 @@ +import { Content, Header, InfoCard, Page } from '@backstage/core-components'; +import { PrimerDemo } from './PrimerDemo'; + +export function PrimerDemoPage() { + return ( + +
+ + + + + + + ); +} diff --git a/packages/app/src/index.tsx b/packages/app/src/index.tsx index 46f3190..355f8ff 100644 --- a/packages/app/src/index.tsx +++ b/packages/app/src/index.tsx @@ -2,5 +2,6 @@ import '@backstage/cli/asset-types'; import ReactDOM from 'react-dom/client'; import App from './App'; import '@backstage/ui/css/styles.css'; +import './styles/brand.css'; ReactDOM.createRoot(document.getElementById('root')!).render(); diff --git a/packages/app/src/styles/brand.css b/packages/app/src/styles/brand.css new file mode 100644 index 0000000..78198c5 --- /dev/null +++ b/packages/app/src/styles/brand.css @@ -0,0 +1,25 @@ +/* + Minimal Backstage UI variable overrides. + These are scoped to the Backstage theme mode attribute and avoid any global resets. + + Note: If a variable name is not used by the current @backstage/ui version, + it is harmless (it will simply be ignored). +*/ + +[data-theme-mode='light'] { + --bui-bg: #fffdf9; + --bui-bg-surface-1: #ffffff; + --bui-bg-surface-2: #f3f4f6; + --bui-fg-primary: #1b1f24; + --bui-fg-secondary: rgba(27, 31, 36, 0.72); + --bui-border: rgba(27, 31, 36, 0.12); +} + +[data-theme-mode='dark'] { + --bui-bg: #0f1115; + --bui-bg-surface-1: #161b22; + --bui-bg-surface-2: #1f2530; + --bui-fg-primary: #e6edf3; + --bui-fg-secondary: rgba(230, 237, 243, 0.72); + --bui-border: rgba(230, 237, 243, 0.16); +} diff --git a/packages/app/src/themes/brandTheme.ts b/packages/app/src/themes/brandTheme.ts new file mode 100644 index 0000000..3e10378 --- /dev/null +++ b/packages/app/src/themes/brandTheme.ts @@ -0,0 +1,64 @@ +import { + createBaseThemeOptions, + createUnifiedTheme, + palettes, +} from '@backstage/theme'; + +import '@fontsource/inter/400.css'; +import '@fontsource/inter/700.css'; + +const BRAND_FONT_FAMILY = 'Inter, Roboto, Helvetica, Arial, sans-serif'; + +const baseLight = createBaseThemeOptions({ palette: palettes.light }); +const baseDark = createBaseThemeOptions({ palette: palettes.dark }); + +const brandColors = { + primary: { + light: '#FF8A2A', + dark: '#FF9A3D', + }, + secondary: { + light: '#F2A65A', + dark: '#F4B26A', + }, +}; + +export const brandLightTheme = createUnifiedTheme({ + ...baseLight, + defaultPageTheme: 'home', + typography: { + ...baseLight.typography, + fontFamily: BRAND_FONT_FAMILY, + }, + palette: { + ...baseLight.palette, + primary: { + main: brandColors.primary.light, + }, + secondary: { + main: brandColors.secondary.light, + }, + }, +}); + +export const brandDarkTheme = createUnifiedTheme({ + ...baseDark, + defaultPageTheme: 'home', + typography: { + ...baseDark.typography, + fontFamily: BRAND_FONT_FAMILY, + }, + palette: { + ...baseDark.palette, + primary: { + main: brandColors.primary.dark, + }, + secondary: { + main: brandColors.secondary.dark, + }, + background: { + ...baseDark.palette.background, + default: '#0F1115', + }, + }, +}); diff --git a/yarn.lock b/yarn.lock index 64ce316..ebf7feb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7687,6 +7687,27 @@ __metadata: languageName: node linkType: hard +"@github/mini-throttle@npm:^2.1.1": + version: 2.1.1 + resolution: "@github/mini-throttle@npm:2.1.1" + checksum: 10c0/a2861c204fb9342084d9710c98c5808e33bc796ac55b6b9796d085605e97e207ebb81fd60f50a9cf63f879df13a23eea504ce6c7185fd378f474a12709f2e59f + languageName: node + linkType: hard + +"@github/relative-time-element@npm:^4.5.0": + version: 4.5.1 + resolution: "@github/relative-time-element@npm:4.5.1" + checksum: 10c0/b486465184a9486d76846b3decf23dbd83b7afdc6c90e054ce45bb30c6f1da3f0811a85c3d61857cff455865d28338f0d8aa67098c04889be5f9a143381ae398 + languageName: node + linkType: hard + +"@github/tab-container-element@npm:^4.8.2": + version: 4.8.2 + resolution: "@github/tab-container-element@npm:4.8.2" + checksum: 10c0/d550460ea7260d5753734a95dc0442bfa209531e22a6cafdb58b32ac22d5e2526534152cde33d155f2e06ff2517a657c0df65a1e9e4a378c9c2fbd4feff5027a + languageName: node + linkType: hard + "@google-cloud/firestore@npm:^7.0.0": version: 7.10.0 resolution: "@google-cloud/firestore@npm:7.10.0" @@ -9167,6 +9188,20 @@ __metadata: languageName: node linkType: hard +"@lit-labs/react@npm:1.2.1": + version: 1.2.1 + resolution: "@lit-labs/react@npm:1.2.1" + checksum: 10c0/c92364101348400a06c3eb45a6384ca7d47c32765fdcad892827b360d0bad6cef7916f9a17744f2f471a5da3d7d73750767b885fc1521cd5e5e724badb71f014 + languageName: node + linkType: hard + +"@lit-labs/ssr-dom-shim@npm:^1.2.0": + version: 1.5.0 + resolution: "@lit-labs/ssr-dom-shim@npm:1.5.0" + checksum: 10c0/811f6c7a13f9ac4dbf2509da7c6b3c44e423daa1be97d5794b2c601bd38bbc544a2c4016c265fa08066a675c6f453839f9ffe72029ac8c813542680f34310051 + languageName: node + linkType: hard + "@manypkg/find-root@npm:^1.1.0": version: 1.1.0 resolution: "@manypkg/find-root@npm:1.1.0" @@ -11192,6 +11227,13 @@ __metadata: languageName: node linkType: hard +"@oddbird/popover-polyfill@npm:^0.5.2": + version: 0.5.2 + resolution: "@oddbird/popover-polyfill@npm:0.5.2" + checksum: 10c0/d9ed7ae0cb760f69ddf64edb0419a77ae74a3dee40dec5c991b84e7c679cdb92760616dd2de46c088fa53072eb4bf7f5d4db5e5d618d9e3e3c32e63a6625c210 + languageName: node + linkType: hard + "@open-draft/deferred-promise@npm:^2.2.0": version: 2.2.0 resolution: "@open-draft/deferred-promise@npm:2.2.0" @@ -11321,6 +11363,79 @@ __metadata: languageName: node linkType: hard +"@primer/behaviors@npm:^1.9.0": + version: 1.9.0 + resolution: "@primer/behaviors@npm:1.9.0" + checksum: 10c0/42dd3d2785ff17252010222582da49a44a0e00f93e337ce3a94225c650a19cb98f0ce29cc7b1549cf9628b299f19129b6fbbe4a018d92b2277a3e59fccff8efa + languageName: node + linkType: hard + +"@primer/live-region-element@npm:^0.7.1": + version: 0.7.2 + resolution: "@primer/live-region-element@npm:0.7.2" + dependencies: + "@lit-labs/ssr-dom-shim": "npm:^1.2.0" + checksum: 10c0/e7143a62be00ad731ffe7ea832400b3e2b4b85e14ce06c48c00eaea99c894c4ec57af37e9f063499c3f9a8df31db086147b0741a41cae4690a7975acf53f922d + languageName: node + linkType: hard + +"@primer/octicons-react@npm:^19.13.0": + version: 19.21.1 + resolution: "@primer/octicons-react@npm:19.21.1" + peerDependencies: + react: ">=16.3" + checksum: 10c0/2aebbd99ab4dd088221a7a3bfc575fc8315cef5b70a4063a9393bdd855fd21ecf558379fd13bcc7283099a241d288387f56381adb79efc98f61c83377f58e90f + languageName: node + linkType: hard + +"@primer/primitives@npm:10.x || 11.x": + version: 11.3.2 + resolution: "@primer/primitives@npm:11.3.2" + checksum: 10c0/0eafdda3c5128caab0cfb2820a31ed3a8d26212be34003857b4491aed33173e8b17ed4bb64829c3fe0a56702dce3932f2785cfe116ccb77fb441e611aa276d17 + languageName: node + linkType: hard + +"@primer/react@npm:^38.6.2": + version: 38.6.2 + resolution: "@primer/react@npm:38.6.2" + dependencies: + "@github/mini-throttle": "npm:^2.1.1" + "@github/relative-time-element": "npm:^4.5.0" + "@github/tab-container-element": "npm:^4.8.2" + "@lit-labs/react": "npm:1.2.1" + "@oddbird/popover-polyfill": "npm:^0.5.2" + "@primer/behaviors": "npm:^1.9.0" + "@primer/live-region-element": "npm:^0.7.1" + "@primer/octicons-react": "npm:^19.13.0" + "@primer/primitives": "npm:10.x || 11.x" + clsx: "npm:^2.1.1" + color2k: "npm:^2.0.3" + deepmerge: "npm:^4.3.1" + focus-visible: "npm:^5.2.1" + history: "npm:^5.0.0" + hsluv: "npm:1.0.1" + lodash.isempty: "npm:^4.4.0" + lodash.isobject: "npm:^3.0.2" + react-compiler-runtime: "npm:^1.0.0" + react-intersection-observer: "npm:^9.16.0" + peerDependencies: + "@types/react": 18.x || 19.x + "@types/react-dom": 18.x || 19.x + "@types/react-is": 18.x || 19.x + react: 18.x || 19.x + react-dom: 18.x || 19.x + react-is: 18.x || 19.x + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + "@types/react-is": + optional: true + checksum: 10c0/3c08c71d03433921d994c8bd3c0ba1da0f707c698a582e332b1a955b0ec9bae9ef3653441ea80e936276aaae9c20194cc7bc33316707752fbaa4f0f159f071e7 + languageName: node + linkType: hard + "@protobufjs/aspromise@npm:^1.1.1, @protobufjs/aspromise@npm:^1.1.2": version: 1.1.2 resolution: "@protobufjs/aspromise@npm:1.1.2" @@ -18536,6 +18651,7 @@ __metadata: "@mui/utils": "npm:^5.15.14" "@mui/x-charts": "npm:^8.0.0" "@playwright/test": "npm:^1.32.3" + "@primer/react": "npm:^38.6.2" "@swc/types": "npm:^0.1.7" "@testing-library/dom": "npm:^9.0.0" "@testing-library/jest-dom": "npm:^6.0.0" @@ -20710,6 +20826,13 @@ __metadata: languageName: node linkType: hard +"color2k@npm:^2.0.3": + version: 2.0.3 + resolution: "color2k@npm:2.0.3" + checksum: 10c0/e7c13d212c9d1abb1690e378bbc0a6fb1751e4b02e9a73ba3b2ade9d54da673834597d342791d577d1ce400ec486c7f92c5098f9fa85cd113bcfde57420a2bb9 + languageName: node + linkType: hard + "color@npm:^3.1.3": version: 3.2.1 resolution: "color@npm:3.2.1" @@ -24967,6 +25090,13 @@ __metadata: languageName: node linkType: hard +"focus-visible@npm:^5.2.1": + version: 5.2.1 + resolution: "focus-visible@npm:5.2.1" + checksum: 10c0/1c0e4e8b22be8684a664acc340efd6a41aafb560ce09979186a1c934de321ce8d6a3d7175c946aab1c87409b0e10f623274d7ce7d42ff16a0e4dc862fa151623 + languageName: node + linkType: hard + "follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.15.6": version: 1.15.9 resolution: "follow-redirects@npm:1.15.9" @@ -26502,6 +26632,13 @@ __metadata: languageName: node linkType: hard +"hsluv@npm:1.0.1": + version: 1.0.1 + resolution: "hsluv@npm:1.0.1" + checksum: 10c0/2c4714266950f8c1d114b1a766ac2c18af4019c4f8256a8b0f5ad14182bf2548b9ceb34e7e1037f679144e20a860b081c0aa2ac2927f781e8ca739cb8288e4e4 + languageName: node + linkType: hard + "html-encoding-sniffer@npm:^3.0.0": version: 3.0.0 resolution: "html-encoding-sniffer@npm:3.0.0" @@ -29964,6 +30101,13 @@ __metadata: languageName: node linkType: hard +"lodash.isempty@npm:^4.4.0": + version: 4.4.0 + resolution: "lodash.isempty@npm:4.4.0" + checksum: 10c0/6c7eaa0802398736809b9e8aed8b8ac1abca9be71788fd719ba9d7f5b4c23e8dc63b7f049df4131713dda30a2fdedc2f655268e9deb8cd5a985dfc934afca194 + languageName: node + linkType: hard + "lodash.isequal@npm:^4.0.0": version: 4.5.0 resolution: "lodash.isequal@npm:4.5.0" @@ -29992,6 +30136,13 @@ __metadata: languageName: node linkType: hard +"lodash.isobject@npm:^3.0.2": + version: 3.0.2 + resolution: "lodash.isobject@npm:3.0.2" + checksum: 10c0/da4c8480d98b16835b59380b2fbd43c54081acd9466febb788ba77c434384349e0bec162d1c4e89f613f21687b2b6d8384d8a112b80da00c78d28d9915a5cdde + languageName: node + linkType: hard + "lodash.isplainobject@npm:^4.0.6": version: 4.0.6 resolution: "lodash.isplainobject@npm:4.0.6" @@ -35207,6 +35358,15 @@ __metadata: languageName: node linkType: hard +"react-compiler-runtime@npm:^1.0.0": + version: 1.0.0 + resolution: "react-compiler-runtime@npm:1.0.0" + peerDependencies: + react: ^17.0.0 || ^18.0.0 || ^19.0.0 || ^0.0.0-experimental + checksum: 10c0/e081192380ae32d18bebaf341071ae8aecf80f4401b188f80e4b77e8d8995bb4c7175b8c3f75e8307019eac2015edf45c7999f788dcfcd99fdbe2ba9a2d465a4 + languageName: node + linkType: hard + "react-copy-to-clipboard@npm:5.1.0": version: 5.1.0 resolution: "react-copy-to-clipboard@npm:5.1.0" @@ -35413,6 +35573,19 @@ __metadata: languageName: node linkType: hard +"react-intersection-observer@npm:^9.16.0": + version: 9.16.0 + resolution: "react-intersection-observer@npm:9.16.0" + peerDependencies: + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + react-dom: + optional: true + checksum: 10c0/2aee5103fb460c6e5a3ab5a4fdc8c69a5215e23699a12d7857f25ba765fed48eacbed94ca835d79edf00c0edcc9c4fbb5bb057a373402d0551718546810e0e48 + languageName: node + linkType: hard + "react-is@npm:^16.13.1, react-is@npm:^16.7.0": version: 16.13.1 resolution: "react-is@npm:16.13.1" From 2a95183e139078fe74dff5bbc1e4b472aff5cdc4 Mon Sep 17 00:00:00 2001 From: Johnny Huynh <27847622+johnnyhuy@users.noreply.github.com> Date: Sat, 27 Dec 2025 23:42:10 +1100 Subject: [PATCH 2/6] feat: Add GitHub Primer theme integration with custom styles and components --- mise.toml | 2 +- packages/app/README-theme.md | 6 +- packages/app/package.json | 1 + packages/app/src/App.tsx | 5 +- packages/app/src/index.tsx | 2 +- packages/backstage-theme-github/package.json | 41 +++++++++ packages/backstage-theme-github/src/index.ts | 90 +++++++++++++++++++ .../backstage-theme-github/src/styles.css | 19 ++++ packages/backstage-theme-github/tsconfig.json | 12 +++ yarn.lock | 18 ++++ 10 files changed, 190 insertions(+), 6 deletions(-) create mode 100644 packages/backstage-theme-github/package.json create mode 100644 packages/backstage-theme-github/src/index.ts create mode 100644 packages/backstage-theme-github/src/styles.css create mode 100644 packages/backstage-theme-github/tsconfig.json diff --git a/mise.toml b/mise.toml index baf79b2..e41fc63 100644 --- a/mise.toml +++ b/mise.toml @@ -43,7 +43,7 @@ run = './scripts/lint' [tasks.test] description = "Run the test suite" -run = 'yarn test' +run = 'yarn test --watchAll=false' [tasks.build] description = "Build the Backstage Docker image" diff --git a/packages/app/README-theme.md b/packages/app/README-theme.md index a7bbdb3..f139173 100644 --- a/packages/app/README-theme.md +++ b/packages/app/README-theme.md @@ -9,7 +9,7 @@ This app uses Backstage’s Unified Theming API (via `UnifiedThemeProvider` + `c ## Where theme tokens live -- Brand themes: `packages/app/src/themes/brandTheme.ts` +- Brand themes: `packages/backstage-theme-github/src/index.ts` (package: `@internal/backstage-theme-github`) - `brandLightTheme` - `brandDarkTheme` - Existing app theme: `packages/app/src/theme/index.ts` (`backstageTheme`) @@ -18,13 +18,13 @@ The brand themes are intentionally subtle and mostly reuse Backstage base palett ## Backstage UI CSS variable overrides -`packages/app/src/styles/brand.css` contains minimal overrides for Backstage UI CSS variables. +`packages/backstage-theme-github/src/styles.css` contains minimal overrides for Backstage UI CSS variables. - The overrides are scoped to: - `[data-theme-mode='light']` - `[data-theme-mode='dark']` - No element resets are applied (to avoid breaking existing Backstage/MUI styling). -- The CSS is imported once from the app entrypoint. +- The CSS is imported once from the app entrypoint via `@internal/backstage-theme-github/src/styles.css`. ## Primer (GitHub design system) integration diff --git a/packages/app/package.json b/packages/app/package.json index f31f2ad..9f049b0 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -45,6 +45,7 @@ "@emotion/styled": "^11.11.5", "@fontsource/inter": "^5.0.18", "@internal/backstage-plugin-plausible": "^0.1.0", + "@internal/backstage-theme-github": "link:../backstage-theme-github", "@mui/icons-material": "^5.15.19", "@mui/joy": "^5.0.0-beta.36", "@mui/material": "^5.15.19", diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index 2d4d4f1..6e13d13 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -45,7 +45,10 @@ import { HomePage } from './components/home/HomePage'; import CssBaseline from '@mui/material/CssBaseline'; import { PlausibleAnalytics } from '@internal/backstage-plugin-plausible'; import { githubAuthApiRef, gitlabAuthApiRef } from '@backstage/core-plugin-api'; -import { brandDarkTheme, brandLightTheme } from './themes/brandTheme'; +import { + brandDarkTheme, + brandLightTheme, +} from '@internal/backstage-theme-github'; import { PrimerDemoPage } from './components/PrimerDemoPage'; const app = createApp({ diff --git a/packages/app/src/index.tsx b/packages/app/src/index.tsx index 355f8ff..98d7b94 100644 --- a/packages/app/src/index.tsx +++ b/packages/app/src/index.tsx @@ -2,6 +2,6 @@ import '@backstage/cli/asset-types'; import ReactDOM from 'react-dom/client'; import App from './App'; import '@backstage/ui/css/styles.css'; -import './styles/brand.css'; +import '@internal/backstage-theme-github/src/styles.css'; ReactDOM.createRoot(document.getElementById('root')!).render(); diff --git a/packages/backstage-theme-github/package.json b/packages/backstage-theme-github/package.json new file mode 100644 index 0000000..08b7f75 --- /dev/null +++ b/packages/backstage-theme-github/package.json @@ -0,0 +1,41 @@ +{ + "name": "@internal/backstage-theme-github", + "version": "0.0.0", + "private": true, + "bundled": true, + "backstage": { + "role": "frontend" + }, + "files": [ + "dist", + "src" + ], + "main": "src/index.ts", + "types": "src/index.ts", + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "clean": "backstage-cli package clean", + "test": "backstage-cli package test", + "lint": "backstage-cli package lint" + }, + "dependencies": { + "@backstage/theme": "^0.7.1", + "@fontsource/inter": "^5.0.18" + }, + "devDependencies": { + "@backstage/cli": "^0.35.0", + "typescript": "~5.3.0" + }, + "eslintConfig": { + "root": false, + "parser": "@typescript-eslint/parser", + "parserOptions": { + "sourceType": "module", + "project": "./tsconfig.json" + }, + "extends": [ + "plugin:@typescript-eslint/recommended" + ] + } +} diff --git a/packages/backstage-theme-github/src/index.ts b/packages/backstage-theme-github/src/index.ts new file mode 100644 index 0000000..9db7304 --- /dev/null +++ b/packages/backstage-theme-github/src/index.ts @@ -0,0 +1,90 @@ +import { + createBaseThemeOptions, + createUnifiedTheme, + palettes, +} from '@backstage/theme'; + +// GitHub Primer-inspired font stack +const BRAND_FONT_FAMILY = + "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, 'Apple Color Emoji', 'Segoe UI Emoji', sans-serif"; + +// Primer-inspired color tokens +const primer = { + light: { + primary: '#0969da', // Blue + secondary: '#8250df', // Purple accent + bgDefault: '#f6f8fa', + bgPaper: '#ffffff', + textPrimary: '#24292f', + textSecondary: '#57606a', + divider: '#d0d7de', + success: '#1a7f37', + warning: '#9a6700', + error: '#cf222e', + info: '#0969da', + }, + dark: { + primary: '#58a6ff', // Blue + secondary: '#a371f7', // Purple accent + bgDefault: '#0d1117', + bgPaper: '#161b22', + textPrimary: '#c9d1d9', + textSecondary: '#8b949e', + divider: '#30363d', + success: '#2ea043', + warning: '#d29922', + error: '#f85149', + info: '#58a6ff', + }, +}; + +const baseLight = createBaseThemeOptions({ palette: palettes.light }); +const baseDark = createBaseThemeOptions({ palette: palettes.dark }); + +export const brandLightTheme = createUnifiedTheme({ + ...baseLight, + defaultPageTheme: 'home', + typography: { + ...baseLight.typography, + fontFamily: BRAND_FONT_FAMILY, + }, + palette: { + ...baseLight.palette, + primary: { main: primer.light.primary }, + secondary: { main: primer.light.secondary }, + success: { main: primer.light.success }, + warning: { main: primer.light.warning }, + error: { main: primer.light.error }, + info: { main: primer.light.info }, + background: { + ...baseLight.palette.background, + default: primer.light.bgDefault, + paper: primer.light.bgPaper, + }, + divider: primer.light.divider, + }, +}); + +export const brandDarkTheme = createUnifiedTheme({ + ...baseDark, + defaultPageTheme: 'home', + typography: { + ...baseDark.typography, + fontFamily: BRAND_FONT_FAMILY, + }, + palette: { + ...baseDark.palette, + primary: { main: primer.dark.primary }, + secondary: { main: primer.dark.secondary }, + success: { main: primer.dark.success }, + warning: { main: primer.dark.warning }, + error: { main: primer.dark.error }, + info: { main: primer.dark.info }, + background: { + ...baseDark.palette.background, + default: primer.dark.bgDefault, + paper: primer.dark.bgPaper, + }, + divider: primer.dark.divider, + }, +}); diff --git a/packages/backstage-theme-github/src/styles.css b/packages/backstage-theme-github/src/styles.css new file mode 100644 index 0000000..c80674e --- /dev/null +++ b/packages/backstage-theme-github/src/styles.css @@ -0,0 +1,19 @@ +/* Minimal Backstage UI variable overrides, scoped by theme mode */ + +[data-theme-mode='light'] { + --bui-bg: #f6f8fa; /* Primer canvasDefault */ + --bui-bg-surface-1: #ffffff; /* Primer canvasInset */ + --bui-bg-surface-2: #f6f8fa; /* subtle surface */ + --bui-fg-primary: #24292f; /* Primer fgDefault */ + --bui-fg-secondary: #57606a; /* Primer fgMuted */ + --bui-border: #d0d7de; /* Primer borderDefault */ +} + +[data-theme-mode='dark'] { + --bui-bg: #0d1117; /* Primer canvasDefault */ + --bui-bg-surface-1: #161b22; /* Primer canvasInset */ + --bui-bg-surface-2: #0d1117; /* subtle surface */ + --bui-fg-primary: #c9d1d9; /* Primer fgDefault */ + --bui-fg-secondary: #8b949e; /* Primer fgMuted */ + --bui-border: #30363d; /* Primer borderDefault */ +} diff --git a/packages/backstage-theme-github/tsconfig.json b/packages/backstage-theme-github/tsconfig.json new file mode 100644 index 0000000..e166afb --- /dev/null +++ b/packages/backstage-theme-github/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "declaration": true, + "emitDeclarationOnly": false, + "composite": true + }, + "include": ["src/**/*"], + "exclude": ["dist", "node_modules"] +} diff --git a/yarn.lock b/yarn.lock index ebf7feb..d03132e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8330,6 +8330,23 @@ __metadata: languageName: unknown linkType: soft +"@internal/backstage-theme-github@link:../backstage-theme-github::locator=app%40workspace%3Apackages%2Fapp": + version: 0.0.0-use.local + resolution: "@internal/backstage-theme-github@link:../backstage-theme-github::locator=app%40workspace%3Apackages%2Fapp" + languageName: node + linkType: soft + +"@internal/backstage-theme-github@workspace:packages/backstage-theme-github": + version: 0.0.0-use.local + resolution: "@internal/backstage-theme-github@workspace:packages/backstage-theme-github" + dependencies: + "@backstage/cli": "npm:^0.35.0" + "@backstage/theme": "npm:^0.7.1" + "@fontsource/inter": "npm:^5.0.18" + typescript: "npm:~5.3.0" + languageName: unknown + linkType: soft + "@internationalized/date@npm:^3.10.1": version: 3.10.1 resolution: "@internationalized/date@npm:3.10.1" @@ -18644,6 +18661,7 @@ __metadata: "@emotion/styled": "npm:^11.11.5" "@fontsource/inter": "npm:^5.0.18" "@internal/backstage-plugin-plausible": "npm:^0.1.0" + "@internal/backstage-theme-github": "link:../backstage-theme-github" "@mui/icons-material": "npm:^5.15.19" "@mui/joy": "npm:^5.0.0-beta.36" "@mui/material": "npm:^5.15.19" From 1d5a0b2cf4439db9d2fdd54a68d3c9490683d473 Mon Sep 17 00:00:00 2001 From: Johnny Huynh <27847622+johnnyhuy@users.noreply.github.com> Date: Sun, 28 Dec 2025 00:56:13 +1100 Subject: [PATCH 3/6] feat: Update package dependencies for Backstage components --- package.json | 5 +- packages/app/package.json | 2 +- yarn.lock | 99 --------------------------------------- 3 files changed, 5 insertions(+), 101 deletions(-) diff --git a/package.json b/package.json index 9c944de..39e9a6c 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,9 @@ "resolutions": { "@types/react": "^18", "@types/react-dom": "^18", + "@backstage/app-defaults": "^1.7.3", + "@backstage/frontend-app-api": "^0.13.3", + "@backstage/core-app-api": "^1.19.3", "isolated-vm": "5.0.4" }, "prettier": "@spotify/prettier-config", @@ -58,4 +61,4 @@ ] }, "packageManager": "yarn@4.3.1" -} +} \ No newline at end of file diff --git a/packages/app/package.json b/packages/app/package.json index 9f049b0..30f85ed 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -89,4 +89,4 @@ "files": [ "dist" ] -} \ No newline at end of file +} diff --git a/yarn.lock b/yarn.lock index d03132e..7ed63fa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2772,29 +2772,6 @@ __metadata: languageName: node linkType: hard -"@backstage/app-defaults@npm:^1.6.2": - version: 1.6.2 - resolution: "@backstage/app-defaults@npm:1.6.2" - dependencies: - "@backstage/core-app-api": "npm:^1.17.0" - "@backstage/core-components": "npm:^0.17.2" - "@backstage/core-plugin-api": "npm:^1.10.7" - "@backstage/plugin-permission-react": "npm:^0.4.34" - "@backstage/theme": "npm:^0.6.6" - "@material-ui/core": "npm:^4.12.2" - "@material-ui/icons": "npm:^4.9.1" - peerDependencies: - "@types/react": ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 - react-dom: ^17.0.0 || ^18.0.0 - react-router-dom: ^6.3.0 - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/f3c53aa2be7e9ba7d59b5ab3c851b79be29d44fcfa51823ec45a528f7319a5b31f6d2ea2a2c4b2cd6925fddef23d45da94cda3f7e553fb02e572b6327e00ccb8 - languageName: node - linkType: hard - "@backstage/app-defaults@npm:^1.7.3": version: 1.7.3 resolution: "@backstage/app-defaults@npm:1.7.3" @@ -3829,34 +3806,6 @@ __metadata: languageName: node linkType: hard -"@backstage/core-app-api@npm:^1.17.0": - version: 1.17.0 - resolution: "@backstage/core-app-api@npm:1.17.0" - dependencies: - "@backstage/config": "npm:^1.3.2" - "@backstage/core-plugin-api": "npm:^1.10.7" - "@backstage/types": "npm:^1.2.1" - "@backstage/version-bridge": "npm:^1.0.11" - "@types/prop-types": "npm:^15.7.3" - history: "npm:^5.0.0" - i18next: "npm:^22.4.15" - lodash: "npm:^4.17.21" - prop-types: "npm:^15.7.2" - react-use: "npm:^17.2.4" - zen-observable: "npm:^0.10.0" - zod: "npm:^3.22.4" - peerDependencies: - "@types/react": ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 - react-dom: ^17.0.0 || ^18.0.0 - react-router-dom: ^6.3.0 - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/e1b473e4e7b9861cd0038bb292e80054bcc7ab5d30274fca1ae9ed1be35f2142eb0cbb67fa0ad9f55aabe6b91409a15342bde859c87df355c70d691732bd477d - languageName: node - linkType: hard - "@backstage/core-app-api@npm:^1.19.3": version: 1.19.3 resolution: "@backstage/core-app-api@npm:1.19.3" @@ -4164,32 +4113,6 @@ __metadata: languageName: node linkType: hard -"@backstage/frontend-app-api@npm:^0.11.2": - version: 0.11.2 - resolution: "@backstage/frontend-app-api@npm:0.11.2" - dependencies: - "@backstage/config": "npm:^1.3.2" - "@backstage/core-app-api": "npm:^1.17.0" - "@backstage/core-plugin-api": "npm:^1.10.7" - "@backstage/errors": "npm:^1.2.7" - "@backstage/frontend-defaults": "npm:^0.2.2" - "@backstage/frontend-plugin-api": "npm:^0.10.2" - "@backstage/types": "npm:^1.2.1" - "@backstage/version-bridge": "npm:^1.0.11" - lodash: "npm:^4.17.21" - zod: "npm:^3.22.4" - peerDependencies: - "@types/react": ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 - react-dom: ^17.0.0 || ^18.0.0 - react-router-dom: ^6.3.0 - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/d8c1d15da096290c8455628673d474c10a1c05d8944f40fb83c7f0dae357171a2c4a04f6d51b6f4f2cdf2baad37dc61a26d217049d555fec73a80c4894ec129a - languageName: node - linkType: hard - "@backstage/frontend-app-api@npm:^0.13.3": version: 0.13.3 resolution: "@backstage/frontend-app-api@npm:0.13.3" @@ -4216,28 +4139,6 @@ __metadata: languageName: node linkType: hard -"@backstage/frontend-defaults@npm:^0.2.2": - version: 0.2.2 - resolution: "@backstage/frontend-defaults@npm:0.2.2" - dependencies: - "@backstage/config": "npm:^1.3.2" - "@backstage/errors": "npm:^1.2.7" - "@backstage/frontend-app-api": "npm:^0.11.2" - "@backstage/frontend-plugin-api": "npm:^0.10.2" - "@backstage/plugin-app": "npm:^0.1.9" - "@react-hookz/web": "npm:^24.0.0" - peerDependencies: - "@types/react": ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 - react-dom: ^17.0.0 || ^18.0.0 - react-router-dom: ^6.3.0 - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/9a186e6c6562ed9b10342cefe7be6763ee589f1ece91b5c387766dd0fb227a9fbdf7dff64c98a3e22a4eed1d80fc4c69244575968f841aeb6feee29ad8c9e5ec - languageName: node - linkType: hard - "@backstage/frontend-defaults@npm:^0.3.4": version: 0.3.4 resolution: "@backstage/frontend-defaults@npm:0.3.4" From 9e639010312fc3cf8a7c1f31d4bfef93261a4e0b Mon Sep 17 00:00:00 2001 From: Johnny Huynh <27847622+johnnyhuy@users.noreply.github.com> Date: Sun, 28 Dec 2025 01:04:18 +1100 Subject: [PATCH 4/6] feat: Update GitHub Primer theme with new light and dark navigation styles --- package.json | 2 +- packages/app/src/App.tsx | 24 ++++---- packages/backstage-theme-github/src/index.ts | 65 ++++++++++++++++++++ 3 files changed, 78 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index 39e9a6c..0d589bf 100644 --- a/package.json +++ b/package.json @@ -61,4 +61,4 @@ ] }, "packageManager": "yarn@4.3.1" -} \ No newline at end of file +} diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index 6e13d13..33a184a 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -95,34 +95,34 @@ const app = createApp({ }, themes: [ { - id: 'default', - title: 'Default', + id: 'brand-light', + title: 'GitHub Light', variant: 'light', - icon: , Provider: ({ children }) => ( - + {children} ), }, { - id: 'brand-light', - title: 'Brand Light', - variant: 'light', + id: 'brand-dark', + title: 'GitHub Dark', + variant: 'dark', Provider: ({ children }) => ( - + {children} ), }, { - id: 'brand-dark', - title: 'Brand Dark', - variant: 'dark', + id: 'default', + title: 'Legacy (Original)', + variant: 'light', + icon: , Provider: ({ children }) => ( - + {children} diff --git a/packages/backstage-theme-github/src/index.ts b/packages/backstage-theme-github/src/index.ts index 9db7304..1cc7958 100644 --- a/packages/backstage-theme-github/src/index.ts +++ b/packages/backstage-theme-github/src/index.ts @@ -1,7 +1,9 @@ import { createBaseThemeOptions, createUnifiedTheme, + genPageTheme, palettes, + shapes, } from '@backstage/theme'; // GitHub Primer-inspired font stack @@ -38,6 +40,23 @@ const primer = { }, }; +const navigation = { + light: { + // GitHub header/nav in light mode is dark + background: '#24292f', + indicator: primer.light.primary, + color: '#d0d7de', + selectedColor: '#ffffff', + }, + dark: { + // GitHub dark header/nav + background: '#010409', + indicator: primer.dark.primary, + color: '#c9d1d9', + selectedColor: '#f0f6fc', + }, +}; + const baseLight = createBaseThemeOptions({ palette: palettes.light }); const baseDark = createBaseThemeOptions({ palette: palettes.dark }); @@ -48,6 +67,14 @@ export const brandLightTheme = createUnifiedTheme({ ...baseLight.typography, fontFamily: BRAND_FONT_FAMILY, }, + pageTheme: { + ...baseLight.pageTheme, + // Make the home header feel more GitHub/Primer (less Backstage-green) + home: genPageTheme({ + colors: [navigation.light.background, primer.light.primary], + shape: shapes.wave2, + }), + }, palette: { ...baseLight.palette, primary: { main: primer.light.primary }, @@ -62,6 +89,22 @@ export const brandLightTheme = createUnifiedTheme({ paper: primer.light.bgPaper, }, divider: primer.light.divider, + navigation: { + ...baseLight.palette.navigation, + ...navigation.light, + }, + }, + components: { + ...baseLight.components, + // Ensure the drawer uses the same nav background (some variants read MUI Drawer styles) + MuiDrawer: { + styleOverrides: { + paper: { + backgroundColor: navigation.light.background, + color: navigation.light.color, + }, + }, + }, }, }); @@ -72,6 +115,13 @@ export const brandDarkTheme = createUnifiedTheme({ ...baseDark.typography, fontFamily: BRAND_FONT_FAMILY, }, + pageTheme: { + ...baseDark.pageTheme, + home: genPageTheme({ + colors: [navigation.dark.background, primer.dark.primary], + shape: shapes.wave2, + }), + }, palette: { ...baseDark.palette, primary: { main: primer.dark.primary }, @@ -86,5 +136,20 @@ export const brandDarkTheme = createUnifiedTheme({ paper: primer.dark.bgPaper, }, divider: primer.dark.divider, + navigation: { + ...baseDark.palette.navigation, + ...navigation.dark, + }, + }, + components: { + ...baseDark.components, + MuiDrawer: { + styleOverrides: { + paper: { + backgroundColor: navigation.dark.background, + color: navigation.dark.color, + }, + }, + }, }, }); From 507ae6e0c9f84faef8fca8449a4f7c79ff1fc2cc Mon Sep 17 00:00:00 2001 From: Johnny Huynh <27847622+johnnyhuy@users.noreply.github.com> Date: Fri, 2 Jan 2026 12:53:34 +1100 Subject: [PATCH 5/6] feat: Integrate Primer Octicons and update theme styles - Added @primer/octicons-react dependency for icon usage. - Replaced existing icons in the Sidebar with Primer Octicons for a consistent look. - Updated HomePage styles to use theme colors for better theming support. - Enhanced GitHub theme with improved typography settings and color palettes. --- packages/app/package.json | 3 +- packages/app/src/components/Root/Root.tsx | 79 ++++---- packages/app/src/components/home/HomePage.tsx | 8 +- packages/backstage-theme-github/src/index.ts | 186 ++++++++++++++---- yarn.lock | 3 +- 5 files changed, 187 insertions(+), 92 deletions(-) diff --git a/packages/app/package.json b/packages/app/package.json index 30f85ed..bd0136f 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -52,6 +52,7 @@ "@mui/styles": "^5.18.0", "@mui/utils": "^5.15.14", "@mui/x-charts": "^8.0.0", + "@primer/octicons-react": "^19.21.1", "@primer/react": "^38.6.2", "history": "^5.0.0", "react": "^18.0.2", @@ -89,4 +90,4 @@ "files": [ "dist" ] -} +} \ No newline at end of file diff --git a/packages/app/src/components/Root/Root.tsx b/packages/app/src/components/Root/Root.tsx index b6c7f49..e6fe8d7 100644 --- a/packages/app/src/components/Root/Root.tsx +++ b/packages/app/src/components/Root/Root.tsx @@ -1,6 +1,5 @@ import { PropsWithChildren } from 'react'; import { styled } from '@mui/material/styles'; -import Home from '@mui/icons-material/Home'; import LogoFull from './LogoFull'; import LogoIcon from './LogoIcon'; import { @@ -9,6 +8,18 @@ import { } from '@backstage/plugin-user-settings'; import { SidebarSearchModal } from '@backstage/plugin-search'; import { NotificationsSidebarItem } from '@backstage/plugin-notifications'; +import { + HomeIcon, + SearchIcon, + ThreeBarsIcon, + RepoIcon, + PlugIcon, + BookIcon, + RocketIcon, + ChecklistIcon, + PulseIcon, + TelescopeIcon, +} from '@primer/octicons-react'; import { Sidebar, sidebarConfig, @@ -21,15 +32,6 @@ import { Link, SidebarExpandButton, } from '@backstage/core-components'; -import MenuIcon from '@mui/icons-material/Menu'; -import SearchIcon from '@mui/icons-material/Search'; -import AutoAwesomeRoundedIcon from '@mui/icons-material/AutoAwesomeRounded'; -import ExtensionRoundedIcon from '@mui/icons-material/ExtensionRounded'; -import MenuBookRoundedIcon from '@mui/icons-material/MenuBookRounded'; -import LocalLibraryRoundedIcon from '@mui/icons-material/LocalLibraryRounded'; -import TouchAppRoundedIcon from '@mui/icons-material/TouchAppRounded'; -import MonitorHeartRoundedIcon from '@mui/icons-material/MonitorHeartRounded'; -import ScoreRoundedIcon from '@mui/icons-material/ScoreRounded'; import { IconComponent } from '@backstage/core-plugin-api'; export enum LocalStorageKeys { @@ -63,6 +65,15 @@ const SidebarLogo = () => { ); }; +const HomeOcticon: IconComponent = () => ; +const RepoOcticon: IconComponent = () => ; +const PlugOcticon: IconComponent = () => ; +const BookOcticon: IconComponent = () => ; +const RocketOcticon: IconComponent = () => ; +const ChecklistOcticon: IconComponent = () => ; +const PulseOcticon: IconComponent = () => ; +const TelescopeOcticon: IconComponent = () => ; + export const Root = ({ children }: PropsWithChildren<{}>) => { if ( window.localStorage.getItem(LocalStorageKeys.SIDEBAR_PIN_STATE) === null @@ -77,30 +88,22 @@ export const Root = ({ children }: PropsWithChildren<{}>) => { - } to="/search"> + } + to="/search" + > - }> + }> {/* Global nav, not org-specific */} - - - - + + + + @@ -108,21 +111,9 @@ export const Root = ({ children }: PropsWithChildren<{}>) => { - - - + + + { return { width: '50vh', borderRadius: theme.shape.borderRadius, - backgroundColor: '#FFF', + backgroundColor: theme.palette.background.paper, }; }); const Header = styled('div')(({ theme }) => ({ display: 'flex', justifyContent: 'space-between', - backgroundColor: '#000', + backgroundColor: theme.palette.background.default, gap: '10px', padding: '20px 40px', backgroundImage: theme.page.backgroundImage, @@ -151,7 +151,7 @@ export const HomePage = () => { sx={{ display: 'flex', flexDirection: 'column', - color: '#FFF', + color: theme.palette.text.primary, }} > @@ -774,7 +774,7 @@ export const HomePage = () => { display: 'flex', flexDirection: 'column', alignItems: 'center', - borderLeft: '1px solid #e0e0e0', + borderLeft: `1px solid ${theme.palette.divider}`, }} >