Skip to content

Commit ee1def6

Browse files
fix(theme): avoid sidebar background color bleeding into page content (#2840)
* avoid sidebar color bleeding into page content Signed-off-by: Karthik <karthik.jk11@gmail.com> * pick the navigation or rhdh colors based on user's config Signed-off-by: Karthik <karthik.jk11@gmail.com> --------- Signed-off-by: Karthik <karthik.jk11@gmail.com>
1 parent 8e3f51f commit ee1def6

8 files changed

Lines changed: 292 additions & 14 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@red-hat-developer-hub/backstage-plugin-theme': patch
3+
---
4+
5+
Align the navigation sidebar with merged `palette.navigation` and `rhdh.general` colors, including submenu rows and selected/active `BackstageSidebarItem` states. Add `rhdh.general.pageInsetBackgroundColor` so the page inset shell can use its own color (defaults match the previous app bar fill; falls back to `appBarBackgroundColor` when unset). Main content area remains on `mainSectionBackgroundColor`.

workspaces/theme/plugins/theme/report.api.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ export interface RHDHThemePalette {
6767
// (undocumented)
6868
general: {
6969
pageInset: string;
70+
pageInsetBackgroundColor: string;
7071
disabled: string;
7172
disabledBackground: string;
7273
paperBackgroundImage: string;

workspaces/theme/plugins/theme/src/darkTheme.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export const darkThemeOverrides: Partial<ThemeConfigPalette> = {
4949
rhdh: {
5050
general: {
5151
pageInset: '1.5rem',
52+
pageInsetBackgroundColor: '#151515',
5253

5354
disabled: '#AAABAC',
5455
disabledBackground: '#444548',

workspaces/theme/plugins/theme/src/lightTheme.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export const lightThemeOverrides: Partial<ThemeConfigPalette> = {
2727
main: '#0066CC',
2828
},
2929
navigation: {
30-
background: '#222427',
30+
background: '#f2f2f2',
3131
indicator: 'transparent',
3232
color: '#151515',
3333
selectedColor: '#151515',
@@ -49,6 +49,7 @@ export const lightThemeOverrides: Partial<ThemeConfigPalette> = {
4949
rhdh: {
5050
general: {
5151
pageInset: '1.5rem',
52+
pageInsetBackgroundColor: '#f2f2f2',
5253

5354
disabled: '#6A6E73',
5455
disabledBackground: '#D2D2D2',

workspaces/theme/plugins/theme/src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export type BackstageThemePalette = UnifiedThemeOptions['palette'];
2121
export interface RHDHThemePalette {
2222
general: {
2323
pageInset: string;
24+
pageInsetBackgroundColor: string;
2425

2526
disabled: string;
2627
disabledBackground: string;

workspaces/theme/plugins/theme/src/utils/createComponents.ts

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { type CSSObject } from '@mui/material/styles';
2222

2323
import { ThemeConfig, ThemeConfigOptions, RHDHThemePalette } from '../types';
2424
import { redHatFontFaces, redHatFonts } from '../fonts';
25+
import { resolveNavigationSidebarColors } from './navigationSidebarColors';
2526

2627
export type Component = {
2728
defaultProps?: unknown;
@@ -616,16 +617,33 @@ export const createComponents = (themeConfig: ThemeConfig): Components => {
616617
}
617618

618619
if (options.sidebars !== 'mui') {
620+
const {
621+
sidebarBackgroundColor,
622+
sidebarItemInteractionBackgroundColor,
623+
navigationItemColor,
624+
navigationSelectedColor,
625+
} = resolveNavigationSidebarColors(themeConfig);
626+
619627
components.BackstageSidebar = {
620628
styleOverrides: {
621629
drawer: {
622630
gap: '0.25rem',
623-
borderRight: `0.5rem solid ${general.sidebarBackgroundColor}`,
631+
borderRight: `0.5rem solid ${sidebarBackgroundColor}`,
624632
paddingBottom: '1.5rem',
625-
backgroundColor: general.sidebarBackgroundColor,
633+
backgroundColor: sidebarBackgroundColor,
626634
'& hr': {
627635
backgroundColor: general.sidebarDividerColor,
628636
},
637+
'& [class*="BackstageSidebarItem-selected-"][class*="BackstageSidebarItem-root-"]':
638+
{
639+
backgroundColor: `${sidebarItemInteractionBackgroundColor} !important`,
640+
color: `${navigationSelectedColor} !important`,
641+
},
642+
643+
'& [class*="BackstageSidebarSubmenuItem-selected-"]': {
644+
background: `${sidebarItemInteractionBackgroundColor} !important`,
645+
color: `${navigationSelectedColor} !important`,
646+
},
629647
},
630648
},
631649
};
@@ -637,7 +655,7 @@ export const createComponents = (themeConfig: ThemeConfig): Components => {
637655
marginLeft: '0.5rem !important',
638656
textDecorationLine: 'none',
639657
'&:hover, &:focus-visible': {
640-
backgroundColor: general.sidebarItemSelectedBackgroundColor,
658+
backgroundColor: sidebarItemInteractionBackgroundColor,
641659
},
642660
},
643661
label: {
@@ -646,15 +664,16 @@ export const createComponents = (themeConfig: ThemeConfig): Components => {
646664
},
647665
},
648666
selected: {
649-
backgroundColor: general.sidebarItemSelectedBackgroundColor,
667+
backgroundColor: sidebarItemInteractionBackgroundColor,
668+
color: navigationSelectedColor,
650669
},
651670
},
652671
};
653672
components.MuiBottomNavigation = {
654673
styleOverrides: {
655674
root: {
656-
backgroundColor: `${general.sidebarBackgroundColor} !important`,
657-
borderColor: `${general.sidebarBackgroundColor} !important`,
675+
backgroundColor: `${sidebarBackgroundColor} !important`,
676+
borderColor: `${sidebarBackgroundColor} !important`,
658677
},
659678
},
660679
};
@@ -664,19 +683,19 @@ export const createComponents = (themeConfig: ThemeConfig): Components => {
664683
},
665684
styleOverrides: {
666685
root: {
667-
color: `${palette.text?.primary} !important`,
668-
backgroundColor: `${general.sidebarBackgroundColor} !important`,
686+
color: `${navigationItemColor} !important`,
687+
backgroundColor: `${sidebarBackgroundColor} !important`,
669688
borderRadius: '6px',
670689
borderTop: '3px solid transparent !important', // default mui selected styling
671690
paddingTop: '6px !important', // default mui selected styling
672691
marginTop: '-1px !important', // default mui selected styling
673692
'&:hover, &:focus-visible': {
674-
backgroundColor: `${general.sidebarItemSelectedBackgroundColor} !important`,
693+
backgroundColor: `${sidebarItemInteractionBackgroundColor} !important`,
675694
},
676695
},
677696
selected: {
678-
backgroundColor: `${general.sidebarItemSelectedBackgroundColor} !important`,
679-
color: `${palette.text?.primary} !important`,
697+
backgroundColor: `${sidebarItemInteractionBackgroundColor} !important`,
698+
color: `${navigationSelectedColor} !important`,
680699
},
681700
},
682701
};
@@ -685,7 +704,7 @@ export const createComponents = (themeConfig: ThemeConfig): Components => {
685704
root: {
686705
// undocumented Backstage makeStyles
687706
"& [class*='makeStyles-overlay-']": {
688-
backgroundColor: `${general.sidebarBackgroundColor} !important`,
707+
backgroundColor: `${sidebarBackgroundColor} !important`,
689708
},
690709
'& hr': {
691710
backgroundColor: general.sidebarDividerColor,
@@ -728,7 +747,8 @@ export const createComponents = (themeConfig: ThemeConfig): Components => {
728747
root: {
729748
// Controls the page inset as in PF6 -- only in desktop view
730749
'@media (min-width: 600px)': {
731-
backgroundColor: general.sidebarBackgroundColor,
750+
backgroundColor:
751+
general.pageInsetBackgroundColor ?? general.appBarBackgroundColor,
732752
// Prevents the main content from scrolling weird
733753
overflowY: 'auto',
734754
// Cancel out the spacing produced by the page inset border when
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Copyright Red Hat, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import type { ThemeConfig } from '../types';
18+
import { getDefaultThemeConfig } from '../rhdh';
19+
import { resolveNavigationSidebarColors } from './navigationSidebarColors';
20+
21+
describe('resolveNavigationSidebarChrome', () => {
22+
const defaultLight = getDefaultThemeConfig('light');
23+
24+
it('matches baseline defaults', () => {
25+
const c = resolveNavigationSidebarColors(defaultLight);
26+
expect(c.sidebarBackgroundColor).toBe(
27+
defaultLight.palette?.rhdh?.general?.sidebarBackgroundColor,
28+
);
29+
expect(c.sidebarItemInteractionBackgroundColor).toBe(
30+
defaultLight.palette?.rhdh?.general?.sidebarItemSelectedBackgroundColor,
31+
);
32+
expect(c.navigationItemColor).toBe(defaultLight.palette?.navigation?.color);
33+
expect(c.navigationSelectedColor).toBe(
34+
defaultLight.palette?.navigation?.selectedColor,
35+
);
36+
});
37+
38+
it('uses palette.navigation.background when only that differs from baseline', () => {
39+
const config = {
40+
...defaultLight,
41+
palette: {
42+
...defaultLight.palette,
43+
navigation: {
44+
...defaultLight.palette?.navigation,
45+
background: '#aabbcc',
46+
},
47+
},
48+
} as ThemeConfig;
49+
expect(resolveNavigationSidebarColors(config).sidebarBackgroundColor).toBe(
50+
'#aabbcc',
51+
);
52+
});
53+
54+
it('uses rhdh.general.sidebarBackgroundColor when only that differs from baseline', () => {
55+
const config = {
56+
...defaultLight,
57+
palette: {
58+
...defaultLight.palette,
59+
rhdh: {
60+
...defaultLight.palette?.rhdh,
61+
general: {
62+
...defaultLight.palette?.rhdh?.general,
63+
sidebarBackgroundColor: '#ddeeff',
64+
},
65+
},
66+
},
67+
} as ThemeConfig;
68+
expect(resolveNavigationSidebarColors(config).sidebarBackgroundColor).toBe(
69+
'#ddeeff',
70+
);
71+
});
72+
73+
it('uses palette.navigation.navItem.hoverBackground when only that differs from baseline', () => {
74+
const config = {
75+
...defaultLight,
76+
palette: {
77+
...defaultLight.palette,
78+
navigation: {
79+
...defaultLight.palette?.navigation,
80+
navItem: {
81+
...defaultLight.palette?.navigation?.navItem,
82+
hoverBackground: '#0a0b0c',
83+
},
84+
},
85+
},
86+
} as ThemeConfig;
87+
expect(
88+
resolveNavigationSidebarColors(config)
89+
.sidebarItemInteractionBackgroundColor,
90+
).toBe('#0a0b0c');
91+
});
92+
});

0 commit comments

Comments
 (0)