Skip to content

Commit

Permalink
feat: support to get the mode of the current Color Theme (#641)
Browse files Browse the repository at this point in the history
  • Loading branch information
kiwiwong authored Jan 27, 2022
1 parent a926e02 commit 57f8fab
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 3 deletions.
7 changes: 6 additions & 1 deletion src/common/__tests__/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { normalizeFlattedObject } from '../utils';
import { normalizeFlattedObject, colorLightOrDark } from '../utils';

describe('Test Utils', () => {
test('The normalizeFlattedObject function', () => {
Expand Down Expand Up @@ -35,4 +35,9 @@ describe('Test Utils', () => {
const normalized = normalizeFlattedObject(testData);
expect(normalized).toEqual(expected);
});

test('The colorLightOrDark function', () => {
expect(colorLightOrDark('#000')).toBe('dark');
expect(colorLightOrDark('rgb(255,255,255)')).toBe('light');
});
});
41 changes: 41 additions & 0 deletions src/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,44 @@ export function normalizeFlattedObject(target: object): object {
}
return normalized;
}

/**
* Determine if a color is light or dark.
* @param color HEX or RGB
*/
export function colorLightOrDark(color: string) {
// Variables for red, green, blue values
let r: number;
let g: number;
let b: number;

// Check the format of the color, HEX or RGB?
if (color.match(/^rgb/)) {
// If RGB --> store the red, green, blue values in separate variables
const matchArray =
color.match(
/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)$/
) || [];
r = +matchArray[1];
g = +matchArray[2];
b = +matchArray[3];
} else {
// If hex --> Convert it to RGB
let rgbNum = +('0x' + color.slice(1, 7));
if (color.length < 5) {
rgbNum = +('0x' + color.slice(1).replace(/./g, '$&$&').slice(0, 6));
}
r = rgbNum >> 16;
g = (rgbNum >> 8) & 255;
b = rgbNum & 255;
}

// HSP (Highly Sensitive Poo) equation from http://alienryderflex.com/hsp.html
const hsp = Math.sqrt(0.299 * (r * r) + 0.587 * (g * g) + 0.114 * (b * b));

// Using the HSP value, determine whether the color is light or dark
if (hsp > 127.5) {
return 'light';
}
return 'dark';
}
5 changes: 5 additions & 0 deletions src/model/colorTheme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ export enum ColorScheme {
HIGH_CONTRAST = 'hc',
}

export enum ColorThemeMode {
dark = 'dark',
light = 'light',
}

export interface IColorTheme {
/**
* The id of component, theme will be applied by this ID
Expand Down
33 changes: 33 additions & 0 deletions src/services/__tests__/colorThemeService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
ColorThemeService,
DEFAULT_THEME_CLASS_NAME,
} from '../theme/colorThemeService';
import { ColorThemeMode, ColorScheme } from 'mo/model/colorTheme';

const DarkTestTheme = {
id: 'Default Test',
Expand Down Expand Up @@ -133,4 +134,36 @@ describe('The Color Theme Service', () => {
colorThemeService.updateTheme(DarkTestTheme);
});
});

test('Should support to get colorThemeMode', () => {
colorThemeService.updateTheme({
...BuiltInColorTheme,
type: ColorScheme.DARK,
});
expect(colorThemeService.getColorThemeMode()).toBe(ColorThemeMode.dark);

colorThemeService.updateTheme({
...BuiltInColorTheme,
type: ColorScheme.LIGHT,
});
expect(colorThemeService.getColorThemeMode()).toBe(
ColorThemeMode.light
);

colorThemeService.updateTheme({
...BuiltInColorTheme,
type: undefined,
colors: {
'molecule.welcomeBackground': '#252526',
},
});
expect(colorThemeService.getColorThemeMode()).toBe(ColorThemeMode.dark);

colorThemeService.updateTheme({
...BuiltInColorTheme,
type: undefined,
colors: {},
});
expect(colorThemeService.getColorThemeMode()).toBe(ColorThemeMode.dark);
});
});
31 changes: 29 additions & 2 deletions src/services/theme/colorThemeService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
*/

import 'reflect-metadata';
import { IColorTheme } from 'mo/model/colorTheme';
import { IColorTheme, ColorThemeMode, ColorScheme } from 'mo/model/colorTheme';
import { singleton } from 'tsyringe';
import { editor as monacoEditor } from 'mo/monaco';
import { applyStyleSheetRules } from 'mo/common/css';
import { getThemeData, convertToCSSVars } from './helper';
import logger from 'mo/common/logger';
import { prefixClaName } from 'mo/common/className';
import { searchById } from 'mo/common/utils';
import { searchById, colorLightOrDark } from 'mo/common/utils';

export interface IColorThemeService {
/**
Expand Down Expand Up @@ -53,6 +53,10 @@ export interface IColorThemeService {
* Reset theme
*/
reset(): void;
/**
* Get the mode('dark' or 'light') of the current Color Theme
*/
getColorThemeMode(): ColorThemeMode;
}

/**
Expand Down Expand Up @@ -153,4 +157,27 @@ export class ColorThemeService implements IColorThemeService {
this.colorThemes = [BuiltInColorTheme];
this.setTheme(BuiltInColorTheme.id);
}

public getColorThemeMode(): ColorThemeMode {
const { colors, type } = this.colorTheme;

// Try to get colorThemeMode from type
if (type === ColorScheme.DARK || type === ColorScheme.HIGH_CONTRAST) {
return ColorThemeMode.dark;
} else if (type === ColorScheme.LIGHT) {
return ColorThemeMode.light;
}

// Try to get colorThemeMode from background color
const background =
colors?.['editor.background'] ||
colors?.['tab.activeBackground'] ||
colors?.['molecule.welcomeBackground'];
if (background) {
return colorLightOrDark(background) as ColorThemeMode;
}

// Default dark
return ColorThemeMode.dark;
}
}

0 comments on commit 57f8fab

Please sign in to comment.