Skip to content

Commit 653e5a5

Browse files
authored
feat(ui/theme): Support styled-components theming; clean up ant theming (#14787)
1 parent bc814fd commit 653e5a5

File tree

23 files changed

+824
-201
lines changed

23 files changed

+824
-201
lines changed

datahub-web-react/.env

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
REACT_APP_THEME_CONFIG=theme_light.config.json
1+
ANT_THEME_CONFIG=ant_theme_v2.json
22
SKIP_PREFLIGHT_CHECK=true
33
REACT_APP_PROXY_TARGET=http://localhost:9002

datahub-web-react/README.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,16 +82,20 @@ you can change two things without rebuilding.
8282

8383
#### Selecting a theme
8484

85-
Theme configurations are stored in `./src/conf/theme`. To select a theme, choose one and update the `REACT_APP_THEME_CONFIG` env variable stored in `.env`.
86-
To change the selected theme, update the `.env` file and re-run `yarn start` from `datahub/datahub-web-react`.
85+
Theme configurations are defined in `./src/conf/theme/themes.ts`. By default, the theme is chosen based on the `REACT_APP_CUSTOM_THEME_ID` env variable in GMS. If no theme is specified, the default themes `themeV2` or `themeV1` are used based on whether the V2 UI is enabled, which is controlled by environment variables `THEME_V2_ENABLED`, `THEME_V2_DEFAULT`, and `THEME_V2_TOGGLEABLE` in GMS. See `metadata-service/configuration/src/main/resources/application.yaml` for more details.
86+
87+
For quick local development, you can set env variable `REACT_APP_THEME` in `.env` to any of the themes defined in `themes.ts`.
88+
89+
We are transitioning away from Ant theming, but still depend on it for some styling. The Ant theme is stored in json files, in `./src/conf/theme`. To select the Ant theme, choose a json file and set env variable `ANT_THEME_CONFIG` in `.env` to the theme's filename, including `.json`, then re-run `yarn start` from `datahub/datahub-web-react`.
8790

8891
#### Editing a theme
8992

90-
To edit an existing theme, the recommendation is to clone one of the existing themes into a new file with the name `<your_themes_name>.config.json`,
91-
and then update the env variable as descibed above. The theme files have three sections, `styles`, `assets` and `content`. The type of the theme configs is specified
92-
in `./src/conf/theme/types.ts`.
93+
To edit an existing theme, the recommendation is to clone one of the existing themes into a new file with the name `<your_themes_name>.ts`, then update `themes.ts` by importing your theme and adding it to the `themes` object. You can also create a json theme by creating a new file in `./src/conf/theme` with the name `<your_themes_name>.config.json`. The theme interface is defined in `./src/conf/theme/types.ts` and has four sections:
94+
95+
`colors` configures semantic color tokens.
96+
These are not yet widely used but will be the primary way to configure colors in the app going forward.
9397

94-
`styles` configure overrides for the apps theming variables.
98+
`styles` configures overrides for the app's deprecated theming variables and for Ant components.
9599

96100
`assets` configures the logo url.
97101

datahub-web-react/src/CustomThemeProvider.tsx

Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,29 @@
1-
import React, { useEffect, useState } from 'react';
1+
import React, { useState } from 'react';
22
import { ThemeProvider } from 'styled-components';
33

4-
import { loadThemeIdFromLocalStorage } from '@app/useSetAppTheme';
5-
import defaultThemeConfig from '@conf/theme/theme_light.config.json';
4+
import { useIsThemeV2 } from '@app/useIsThemeV2';
5+
import { useCustomThemeId } from '@app/useSetAppTheme';
6+
import themes from '@conf/theme/themes';
67
import { Theme } from '@conf/theme/types';
78
import { CustomThemeContext } from '@src/customThemeContext';
89

910
interface Props {
1011
children: React.ReactNode;
11-
skipSetTheme?: boolean;
1212
}
1313

14-
const CustomThemeProvider = ({ children, skipSetTheme }: Props) => {
15-
const [currentTheme, setTheme] = useState<Theme>(defaultThemeConfig);
16-
const customThemeId = loadThemeIdFromLocalStorage();
14+
const CustomThemeProvider = ({ children }: Props) => {
15+
// Note: AppConfigContext not provided yet, so both of these calls rely on the DEFAULT_APP_CONFIG
16+
const isThemeV2 = useIsThemeV2();
17+
const customThemeId = useCustomThemeId();
1718

18-
useEffect(() => {
19-
// use provided customThemeId and set in useSetAppTheme.tsx if it exists
20-
if (customThemeId) return;
21-
22-
if (import.meta.env.DEV) {
23-
import(/* @vite-ignore */ `./conf/theme/${import.meta.env.REACT_APP_THEME_CONFIG}`).then((theme) => {
24-
setTheme(theme);
25-
});
26-
} else if (!skipSetTheme) {
27-
// Send a request to the server to get the theme config.
28-
fetch(`assets/conf/theme/${import.meta.env.REACT_APP_THEME_CONFIG}`)
29-
.then((response) => response.json())
30-
.then((theme) => {
31-
setTheme(theme);
32-
});
33-
}
34-
}, [skipSetTheme, customThemeId]);
19+
// Note: If custom theme id is a json file, it will only be loaded later in useSetAppTheme
20+
const defaultTheme = isThemeV2 ? themes.themeV2 : themes.themeV1;
21+
const customTheme = customThemeId ? themes[customThemeId] : null;
22+
const [theme, setTheme] = useState<Theme>(customTheme ?? defaultTheme);
3523

3624
return (
37-
<CustomThemeContext.Provider value={{ theme: currentTheme, updateTheme: setTheme }}>
38-
<ThemeProvider theme={currentTheme}>{children}</ThemeProvider>
25+
<CustomThemeContext.Provider value={{ theme, updateTheme: setTheme }}>
26+
<ThemeProvider theme={theme}>{children}</ThemeProvider>
3927
</CustomThemeContext.Provider>
4028
);
4129
};

datahub-web-react/src/app/ingest/source/builder/__tests__/DefineRecipeStep.test.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ import { ThemeProvider } from 'styled-components';
55

66
import { DefineRecipeStep } from '@app/ingest/source/builder/DefineRecipeStep';
77
import { SourceConfig } from '@app/ingest/source/builder/types';
8-
import defaultThemeConfig from '@conf/theme/theme_light.config.json';
8+
import themeV1 from '@conf/theme/themeV1';
99

1010
describe('DefineRecipeStep', () => {
1111
it('should render the RecipeBuilder if the type is in CONNECTORS_WITH_FORM', () => {
1212
const { getByText, queryByText } = render(
13-
<ThemeProvider theme={defaultThemeConfig}>
13+
<ThemeProvider theme={themeV1}>
1414
<MockedProvider>
1515
<DefineRecipeStep
1616
state={{ type: 'snowflake' }}
@@ -31,7 +31,7 @@ describe('DefineRecipeStep', () => {
3131

3232
it('should not render the RecipeBuilder if the type is not in CONNECTORS_WITH_FORM', () => {
3333
const { getByText, queryByText } = render(
34-
<ThemeProvider theme={defaultThemeConfig}>
34+
<ThemeProvider theme={themeV1}>
3535
<MockedProvider>
3636
<DefineRecipeStep
3737
state={{ type: 'glue' }}

datahub-web-react/src/app/ingestV2/source/__tests__/tests_utils.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,7 @@ describe('formatTimezone', () => {
567567
expect(['EST', 'EDT']).toContain(nycAbbr);
568568

569569
const londonAbbr = formatTimezone('Europe/London');
570-
expect(['GMT+1', 'BST']).toContain(londonAbbr);
570+
expect(['GMT+1', 'BST', 'GMT']).toContain(londonAbbr);
571571

572572
// Tokyo doesn't observe DST, so it's always GMT+9
573573
expect(formatTimezone('Asia/Tokyo')).toBe('GMT+9');

datahub-web-react/src/app/ingestV2/source/builder/__tests__/DefineRecipeStep.test.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ import { ThemeProvider } from 'styled-components';
55

66
import { DefineRecipeStep } from '@app/ingestV2/source/builder/DefineRecipeStep';
77
import { SourceConfig } from '@app/ingestV2/source/builder/types';
8-
import defaultThemeConfig from '@conf/theme/theme_light.config.json';
8+
import themeV2 from '@conf/theme/themeV2';
99

1010
describe('DefineRecipeStep', () => {
1111
it('should render the RecipeBuilder if the type is in CONNECTORS_WITH_FORM', () => {
1212
const { getByText, queryByText } = render(
13-
<ThemeProvider theme={defaultThemeConfig}>
13+
<ThemeProvider theme={themeV2}>
1414
<MockedProvider>
1515
<DefineRecipeStep
1616
state={{ type: 'snowflake' }}
@@ -31,7 +31,7 @@ describe('DefineRecipeStep', () => {
3131

3232
it('should not render the RecipeBuilder if the type is not in CONNECTORS_WITH_FORM', () => {
3333
const { getByText, queryByText } = render(
34-
<ThemeProvider theme={defaultThemeConfig}>
34+
<ThemeProvider theme={themeV2}>
3535
<MockedProvider>
3636
<DefineRecipeStep
3737
state={{ type: 'glue' }}

datahub-web-react/src/app/useSetAppTheme.tsx

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@ import { useEffect } from 'react';
22

33
import { useAppConfig } from '@app/useAppConfig';
44
import { useIsThemeV2 } from '@app/useIsThemeV2';
5+
import themes from '@conf/theme/themes';
56
import { useCustomTheme } from '@src/customThemeContext';
67

7-
// add new theme ids here
8-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
9-
enum ThemeId {}
10-
11-
function useCustomThemeId() {
8+
export function useCustomThemeId(): string | null {
129
const { config, loaded } = useAppConfig();
1310

11+
if (import.meta.env.REACT_APP_THEME) {
12+
return import.meta.env.REACT_APP_THEME;
13+
}
14+
1415
if (!loaded) {
1516
return loadThemeIdFromLocalStorage();
1617
}
@@ -20,7 +21,6 @@ function useCustomThemeId() {
2021

2122
export function useSetAppTheme() {
2223
const isThemeV2 = useIsThemeV2();
23-
const { config } = useAppConfig();
2424
const { updateTheme } = useCustomTheme();
2525
const customThemeId = useCustomThemeId();
2626

@@ -29,14 +29,24 @@ export function useSetAppTheme() {
2929
}, [customThemeId]);
3030

3131
useEffect(() => {
32-
// here is where we can start adding new custom themes based on customThemeId
33-
34-
if (isThemeV2) {
35-
import('../conf/theme/theme_v2.config.json').then((theme) => updateTheme(theme));
32+
if (customThemeId && customThemeId.endsWith('.json')) {
33+
if (import.meta.env.DEV) {
34+
import(/* @vite-ignore */ `./conf/theme/${customThemeId}`).then((theme) => {
35+
updateTheme(theme);
36+
});
37+
} else {
38+
fetch(`assets/conf/theme/${customThemeId}`)
39+
.then((response) => response.json())
40+
.then((theme) => {
41+
updateTheme(theme);
42+
});
43+
}
44+
} else if (customThemeId && themes[customThemeId]) {
45+
updateTheme(themes[customThemeId]);
3646
} else {
37-
import('../conf/theme/theme_light.config.json').then((theme) => updateTheme(theme));
47+
updateTheme(isThemeV2 ? themes.themeV2 : themes.themeV1);
3848
}
39-
}, [config, isThemeV2, updateTheme, customThemeId]);
49+
}, [customThemeId, isThemeV2, updateTheme]);
4050
}
4151

4252
function setThemeIdLocalStorage(customThemeId: string | null) {
@@ -49,7 +59,7 @@ function setThemeIdLocalStorage(customThemeId: string | null) {
4959

5060
const CUSTOM_THEME_ID_KEY = 'customThemeId';
5161

52-
export function loadThemeIdFromLocalStorage(): string | null {
62+
function loadThemeIdFromLocalStorage(): string | null {
5363
return localStorage.getItem(CUSTOM_THEME_ID_KEY);
5464
}
5565

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"primary-color": "#1890ff",
3+
"layout-header-background": "white",
4+
"layout-header-color": "#434343",
5+
"layout-body-background": "white",
6+
"component-background": "white",
7+
"body-background": "white",
8+
"border-color-base": "#ececec",
9+
"text-color": "fade(black, 85%)",
10+
"text-color-secondary": "fade(black, 45%)",
11+
"heading-color": "fade(black, 85%)",
12+
"background-color-light": "hsv(0, 0, 98%)",
13+
"divider-color": "fade(black, 6%)",
14+
"disabled-color": "fade(black, 25%)",
15+
"steps-nav-arrow-color": "fade(black, 25%)",
16+
"highlight-color": "#E6F4FF"
17+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"primary-color": "#533FD1",
3+
"link-color": "#533FD1",
4+
"layout-header-background": "white",
5+
"layout-header-color": "#434343",
6+
"layout-body-background": "white",
7+
"component-background": "white",
8+
"body-background": "white",
9+
"border-color-base": "#ececec",
10+
"text-color": "fade(black, 85%)",
11+
"text-color-secondary": "fade(black, 45%)",
12+
"heading-color": "fade(black, 85%)",
13+
"background-color-light": "hsv(0, 0, 98%)",
14+
"divider-color": "fade(black, 6%)",
15+
"disabled-color": "fade(black, 25%)",
16+
"steps-nav-arrow-color": "fade(black, 25%)",
17+
"highlight-color": "#ece9f8"
18+
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
// Should not be imported directly
2+
export default {
3+
gray0: '#FFFFFF',
4+
gray100: '#EBECF0',
5+
gray200: '#F5F6FA',
6+
gray300: '#E9EAEE',
7+
gray400: '#F9FAFC',
8+
gray500: '#A3A7B9',
9+
gray600: '#8088A3',
10+
gray700: '#5F6685',
11+
gray800: '#374066',
12+
gray900: '#323A5D',
13+
gray1000: '#272D48',
14+
gray1100: '#1E2338',
15+
gray1200: '#171B2B',
16+
green0: '#F1F8EE',
17+
green100: '#E1F0D6',
18+
green150: '#ABD58B',
19+
green200: '#248F5B',
20+
green300: '#0D7543',
21+
mudgreen0: '#F7FBF4',
22+
mudgreen100: '#D5E9C9',
23+
mudgreen200: '#C0DEAF',
24+
mudgreen300: '#A4CF8A',
25+
mudgreen400: '#92C573',
26+
mudgreen500: '#77B750',
27+
mudgreen600: '#6CA749',
28+
mudgreen700: '#548239',
29+
mudgreen800: '#41652C',
30+
mudgreen900: '#324D22',
31+
darkgreen0: '#E8F5E9',
32+
darkgreen100: '#C7E5C8',
33+
darkgreen200: '#81C684',
34+
darkgreen300: '#1F7523',
35+
brown0: '#EDEDED',
36+
brown100: '#BCAAA4',
37+
brown200: '#BCAAA4',
38+
brown300: '#5D4037',
39+
trueyellow0: '#FFF8E1',
40+
trueyellow100: '#FFE082',
41+
trueyellow200: '#FBC02D',
42+
trueyellow300: '#9F642F',
43+
tangerine0: '#FFF3E0',
44+
tangerine100: '#FFD8B1',
45+
tangerine200: '#FFD8B1',
46+
tangerine300: '#BF4636',
47+
orange0: '#FFF5F0',
48+
orange100: '#FFE6DA',
49+
orange200: '#FFC0A4',
50+
orange300: '#FF9B6D',
51+
orange400: '#FF8348',
52+
orange500: '#FF6A24',
53+
orange600: '#FF5D13',
54+
orange700: '#FF4F01',
55+
red0: '#FBF3EF',
56+
red50: '#EEB4B4',
57+
red100: '#E54D1F',
58+
red200: '#D23939',
59+
red300: '#C4360B',
60+
wine0: '#F6D5D5',
61+
wine100: '#F3DACE',
62+
wine200: '#F2C1C1',
63+
wine300: '#ECA5A5',
64+
wine400: '#E99393',
65+
wine500: '#E37878',
66+
wine600: '#CF6D6D',
67+
wine700: '#A15555',
68+
wine800: '#7D4242',
69+
wine900: '#5F3232',
70+
yellow0: '#FFFAEB',
71+
yellow100: '#FFF1C7',
72+
yellow200: '#FCEDC7',
73+
yellow300: '#FAE4AB',
74+
yellow400: '#F8D785',
75+
yellow500: '#F6D06D',
76+
yellow600: '#EEAE09',
77+
yellow700: '#EE9521',
78+
yellow800: '#C77100',
79+
violet0: '#F1F3FD',
80+
cyan00: '#E0F2F1',
81+
cyan100: '#80DEEA',
82+
cyan200: '#29C7DC',
83+
cyan300: '#10737F',
84+
cobalt0: '#E8EAF6',
85+
trueblue0: '#E3F2FD',
86+
trueblue100: '#90CAF9',
87+
trueblue200: '#90CAF9',
88+
trueblue300: '#0764C0',
89+
cobalt100: '#C5CAE9',
90+
cobalt200: '#7A85CD',
91+
cobalt300: '#303F9F',
92+
blue0: '#F1FBFE',
93+
seafoam0: '#E0F7FA',
94+
seafoam100: '#80CBC4',
95+
seafoam200: '#80CBC4',
96+
seafoam300: '#20594B',
97+
olive0: '#F1F8E9',
98+
olive100: '#C5E1A5',
99+
olive200: '#79B03B',
100+
olive300: '#417811',
101+
violet100: '#E5E2F8',
102+
violet200: '#CAC3F1',
103+
violet300: '#B0A7EA',
104+
violet400: '#8C7EE0',
105+
violet500: '#705EE4',
106+
violet600: '#533FD1',
107+
violet700: '#4B39BC',
108+
violet800: '#4232A7',
109+
violet900: '#3E2F9D',
110+
violet1000: '#32267D',
111+
violet1100: '#251C5E',
112+
violet1200: '#1D1649',
113+
blue100: '#EFF8FC',
114+
blue200: '#E6F5FB',
115+
blue300: '#CCEBF6',
116+
blue400: '#5ABDE1',
117+
blue500: '#51AACB',
118+
blue600: '#4897B4',
119+
blue700: '#09739A',
120+
blue800: '#367187',
121+
blue900: '#285565',
122+
blue1200: '#1F424F',
123+
lavender0: '#F3E5F5',
124+
lavender100: '#CE93D8',
125+
lavender200: '#B45AC3',
126+
lavender300: '#7B1FA2',
127+
pink0: '#FCF2F2',
128+
pink100: '#FCE4EC',
129+
pink200: '#F8BBD0',
130+
pink300: '#EA5791',
131+
pink400: '#C2185B',
132+
};

0 commit comments

Comments
 (0)