Skip to content

Commit 57f8fab

Browse files
authored
feat: support to get the mode of the current Color Theme (#641)
1 parent a926e02 commit 57f8fab

File tree

5 files changed

+114
-3
lines changed

5 files changed

+114
-3
lines changed

src/common/__tests__/utils.test.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { normalizeFlattedObject } from '../utils';
1+
import { normalizeFlattedObject, colorLightOrDark } from '../utils';
22

33
describe('Test Utils', () => {
44
test('The normalizeFlattedObject function', () => {
@@ -35,4 +35,9 @@ describe('Test Utils', () => {
3535
const normalized = normalizeFlattedObject(testData);
3636
expect(normalized).toEqual(expected);
3737
});
38+
39+
test('The colorLightOrDark function', () => {
40+
expect(colorLightOrDark('#000')).toBe('dark');
41+
expect(colorLightOrDark('rgb(255,255,255)')).toBe('light');
42+
});
3843
});

src/common/utils.ts

+41
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,44 @@ export function normalizeFlattedObject(target: object): object {
106106
}
107107
return normalized;
108108
}
109+
110+
/**
111+
* Determine if a color is light or dark.
112+
* @param color HEX or RGB
113+
*/
114+
export function colorLightOrDark(color: string) {
115+
// Variables for red, green, blue values
116+
let r: number;
117+
let g: number;
118+
let b: number;
119+
120+
// Check the format of the color, HEX or RGB?
121+
if (color.match(/^rgb/)) {
122+
// If RGB --> store the red, green, blue values in separate variables
123+
const matchArray =
124+
color.match(
125+
/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)$/
126+
) || [];
127+
r = +matchArray[1];
128+
g = +matchArray[2];
129+
b = +matchArray[3];
130+
} else {
131+
// If hex --> Convert it to RGB
132+
let rgbNum = +('0x' + color.slice(1, 7));
133+
if (color.length < 5) {
134+
rgbNum = +('0x' + color.slice(1).replace(/./g, '$&$&').slice(0, 6));
135+
}
136+
r = rgbNum >> 16;
137+
g = (rgbNum >> 8) & 255;
138+
b = rgbNum & 255;
139+
}
140+
141+
// HSP (Highly Sensitive Poo) equation from http://alienryderflex.com/hsp.html
142+
const hsp = Math.sqrt(0.299 * (r * r) + 0.587 * (g * g) + 0.114 * (b * b));
143+
144+
// Using the HSP value, determine whether the color is light or dark
145+
if (hsp > 127.5) {
146+
return 'light';
147+
}
148+
return 'dark';
149+
}

src/model/colorTheme.ts

+5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ export enum ColorScheme {
1616
HIGH_CONTRAST = 'hc',
1717
}
1818

19+
export enum ColorThemeMode {
20+
dark = 'dark',
21+
light = 'light',
22+
}
23+
1924
export interface IColorTheme {
2025
/**
2126
* The id of component, theme will be applied by this ID

src/services/__tests__/colorThemeService.test.ts

+33
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
ColorThemeService,
88
DEFAULT_THEME_CLASS_NAME,
99
} from '../theme/colorThemeService';
10+
import { ColorThemeMode, ColorScheme } from 'mo/model/colorTheme';
1011

1112
const DarkTestTheme = {
1213
id: 'Default Test',
@@ -133,4 +134,36 @@ describe('The Color Theme Service', () => {
133134
colorThemeService.updateTheme(DarkTestTheme);
134135
});
135136
});
137+
138+
test('Should support to get colorThemeMode', () => {
139+
colorThemeService.updateTheme({
140+
...BuiltInColorTheme,
141+
type: ColorScheme.DARK,
142+
});
143+
expect(colorThemeService.getColorThemeMode()).toBe(ColorThemeMode.dark);
144+
145+
colorThemeService.updateTheme({
146+
...BuiltInColorTheme,
147+
type: ColorScheme.LIGHT,
148+
});
149+
expect(colorThemeService.getColorThemeMode()).toBe(
150+
ColorThemeMode.light
151+
);
152+
153+
colorThemeService.updateTheme({
154+
...BuiltInColorTheme,
155+
type: undefined,
156+
colors: {
157+
'molecule.welcomeBackground': '#252526',
158+
},
159+
});
160+
expect(colorThemeService.getColorThemeMode()).toBe(ColorThemeMode.dark);
161+
162+
colorThemeService.updateTheme({
163+
...BuiltInColorTheme,
164+
type: undefined,
165+
colors: {},
166+
});
167+
expect(colorThemeService.getColorThemeMode()).toBe(ColorThemeMode.dark);
168+
});
136169
});

src/services/theme/colorThemeService.ts

+29-2
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
*/
55

66
import 'reflect-metadata';
7-
import { IColorTheme } from 'mo/model/colorTheme';
7+
import { IColorTheme, ColorThemeMode, ColorScheme } from 'mo/model/colorTheme';
88
import { singleton } from 'tsyringe';
99
import { editor as monacoEditor } from 'mo/monaco';
1010
import { applyStyleSheetRules } from 'mo/common/css';
1111
import { getThemeData, convertToCSSVars } from './helper';
1212
import logger from 'mo/common/logger';
1313
import { prefixClaName } from 'mo/common/className';
14-
import { searchById } from 'mo/common/utils';
14+
import { searchById, colorLightOrDark } from 'mo/common/utils';
1515

1616
export interface IColorThemeService {
1717
/**
@@ -53,6 +53,10 @@ export interface IColorThemeService {
5353
* Reset theme
5454
*/
5555
reset(): void;
56+
/**
57+
* Get the mode('dark' or 'light') of the current Color Theme
58+
*/
59+
getColorThemeMode(): ColorThemeMode;
5660
}
5761

5862
/**
@@ -153,4 +157,27 @@ export class ColorThemeService implements IColorThemeService {
153157
this.colorThemes = [BuiltInColorTheme];
154158
this.setTheme(BuiltInColorTheme.id);
155159
}
160+
161+
public getColorThemeMode(): ColorThemeMode {
162+
const { colors, type } = this.colorTheme;
163+
164+
// Try to get colorThemeMode from type
165+
if (type === ColorScheme.DARK || type === ColorScheme.HIGH_CONTRAST) {
166+
return ColorThemeMode.dark;
167+
} else if (type === ColorScheme.LIGHT) {
168+
return ColorThemeMode.light;
169+
}
170+
171+
// Try to get colorThemeMode from background color
172+
const background =
173+
colors?.['editor.background'] ||
174+
colors?.['tab.activeBackground'] ||
175+
colors?.['molecule.welcomeBackground'];
176+
if (background) {
177+
return colorLightOrDark(background) as ColorThemeMode;
178+
}
179+
180+
// Default dark
181+
return ColorThemeMode.dark;
182+
}
156183
}

0 commit comments

Comments
 (0)