Skip to content

Commit 7222df0

Browse files
feat: update versions colors
1 parent 5ff0120 commit 7222df0

File tree

4 files changed

+99
-33
lines changed

4 files changed

+99
-33
lines changed

src/containers/Versions/Versions.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export function VersionsContainer({cluster, loading}: VersionsContainerProps) {
3232
{tablets: false, fieldsRequired: ['SystemState', 'SubDomainKey']},
3333
{pollingInterval: autoRefreshInterval},
3434
);
35-
const versionToColor = useVersionToColorMap();
35+
const versionToColor = useVersionToColorMap(cluster);
3636

3737
const versionsValues = useGetVersionValues({cluster, versionToColor, clusterLoading: loading});
3838

src/utils/clusterVersionColors.ts

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@ import uniqBy from 'lodash/uniqBy';
33
import type {MetaClusterVersion} from '../types/api/meta';
44
import type {VersionToColorMap} from '../types/versions';
55

6-
import {COLORS, DEFAULT_COLOR, getMinorVersion, hashCode} from './versions';
6+
import {
7+
DEFAULT_COLOR,
8+
getColors,
9+
getMinorVersion,
10+
getMinorVersionColorVariant,
11+
hashCode,
12+
} from './versions';
713

814
const UNDEFINED_COLOR_INDEX = '__no_color__';
915

@@ -28,6 +34,8 @@ export const getVersionMap = (
2834
export const getVersionColors = (versionMap: VersionsMap) => {
2935
const versionToColor: VersionToColorMap = new Map();
3036

37+
const colors = getColors();
38+
3139
for (const [baseColorIndex, item] of versionMap) {
3240
Array.from(item)
3341
// descending by version name: newer versions come first,
@@ -38,13 +46,16 @@ export const getVersionColors = (versionMap: VersionsMap) => {
3846
versionToColor.set(minor, DEFAULT_COLOR);
3947
} else {
4048
// baseColorIndex is numeric as we check if it is UNDEFINED_COLOR_INDEX before
41-
const currentColorIndex = Number(baseColorIndex) % COLORS.length;
49+
const currentColorIndex = Number(baseColorIndex) % colors.length;
4250
const minorQuantity = item.size;
43-
const majorColor = COLORS[currentColorIndex];
44-
const opacityPercent = Math.max(100 - minorIndex * (100 / minorQuantity), 20);
45-
const hexOpacity = Math.round((opacityPercent * 255) / 100).toString(16);
46-
const versionColor = `${majorColor}${hexOpacity}`;
47-
versionToColor.set(minor, versionColor);
51+
52+
const minorColorVariant = getMinorVersionColorVariant(
53+
minorIndex,
54+
minorQuantity,
55+
);
56+
const minorColor = colors[currentColorIndex][minorColorVariant];
57+
58+
versionToColor.set(minor, minorColor);
4859
}
4960
});
5061
}

src/utils/index.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,21 @@ export function normalizePathSlashes(path: string) {
1717
// (?<!:) - negative lookbehind - ignore parts that start with :
1818
return path.replaceAll(/(?<!:)\/\/+/g, '/');
1919
}
20+
21+
export function getSystemTheme() {
22+
if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {
23+
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
24+
} else {
25+
return 'light';
26+
}
27+
}
28+
29+
export function getTheme() {
30+
const savedTheme = localStorage.getItem('theme') || 'light';
31+
32+
if (savedTheme === 'system') {
33+
return getSystemTheme();
34+
}
35+
36+
return savedTheme.includes('dark') ? 'dark' : 'light';
37+
}

src/utils/versions/getVersionsColors.ts

Lines changed: 62 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import {getTheme} from '..';
12
import type {VersionToColorMap, VersionsMap} from '../../types/versions';
23

34
import {getMajorVersion, getMinorVersion} from './parseVersion';
@@ -9,23 +10,58 @@ export const hashCode = (s: string) => {
910
}, 0);
1011
};
1112

12-
// TODO: colors used in charts as well, need to move to constants
13-
// 11 distinct colors from https://mokole.com/palette.html
14-
export const COLORS = [
15-
'#008000', // green
16-
'#4169e1', // royalblue
17-
'#ffd700', // gold
18-
'#ff8c00', // darkorange
19-
'#808000', // olive
20-
'#e9967a', // darksalmon
21-
'#ff1493', // deeppink
22-
'#00bfff', // deepskyblue
23-
'#da70d6', // orchid
24-
'#8b4513', //saddlebrown
25-
'#b22222', // firebrick
13+
const DARK_COLORS = [
14+
['#D50C38', '#FF2051', '#FB3A64', '#FF6989'],
15+
['#EB3320', '#FF503E', '#FF8376', '#FFA399'],
16+
['#F47B10', '#FF9B43', '#FFB06A', '#FFC693'],
17+
['#FFEA00', '#FFEE31', '#FFF480', '#FFF8A9'],
18+
['#83D400', '#B1FF33', '#CBFF78', '#DDFFA7'],
19+
['#27C98B', '#16FFA6', '#4CFFBA', '#9BFFD8'],
20+
['#0EDBDE', '#0CFBFF', '#63FDFF', '#B1FEFF'],
21+
['#2059FF', '#4070FF', '#658BFF', '#A1B9FF'],
22+
['#AB07E3', '#C92CFF', '#DD78FF', '#E79FFF'],
23+
['#E71498', '#FF34B3', '#FF75CB', '#FFB0E1'],
2624
];
2725

28-
export const DEFAULT_COLOR = '#3cb371'; // mediumseagreen
26+
const LIGHT_COLORS = [
27+
['#F4315B', '#FF426B', '#FF7391', '#FF8BA4'],
28+
['#FF6050', '#FF7A6D', '#FFAFA6', '#FFBCB5'],
29+
['#FF9233', '#FFAD65', '#FFC593', '#FFD3AC'],
30+
['#FFEA00', '#FFEE31', '#FFF480', '#FFF8A9'],
31+
['#A1EE26', '#B1FF33', '#CBFF78', '#DDFFA7'],
32+
['#31EBA4', '#16FFA6', '#4CFFBA', '#9BFFD8'],
33+
['#2EE4E8', '#0CFBFF', '#63FDFF', '#B1FEFF'],
34+
['#386BFF', '#4070FF', '#658BFF', '#A1B9FF'],
35+
['#C73AF7', '#C92CFF', '#DD78FF', '#E79FFF'],
36+
['#FF49BB', '#FF34B3', '#FF75CB', '#FFB0E1'],
37+
];
38+
39+
export function getColors() {
40+
return getTheme() === 'dark' ? DARK_COLORS : LIGHT_COLORS;
41+
}
42+
43+
/** Calculates sub color index */
44+
export function getMinorVersionColorVariant(minorIndex: number, minorQuantity: number) {
45+
// We have 4 sub colors for each color
46+
// For 4+ minors first 25% will be colored with the first most bright color
47+
// Every next 25% will be colored with corresponding color
48+
// Do not use all colors if there are less than 4 minors
49+
50+
if (minorQuantity === 1) {
51+
return 0;
52+
}
53+
if (minorQuantity === 2) {
54+
return Math.floor((2 * minorIndex) / minorQuantity);
55+
}
56+
if (minorQuantity === 3) {
57+
return Math.floor((3 * minorIndex) / minorQuantity);
58+
}
59+
60+
return Math.floor((4 * minorIndex) / minorQuantity);
61+
}
62+
63+
// TODO: replace with color suggested by designer
64+
export const DEFAULT_COLOR = 'saddlebrown';
2965

3066
export const getVersionsMap = (versions: string[], initialMap: VersionsMap = new Map()) => {
3167
versions.forEach((version) => {
@@ -47,20 +83,23 @@ export const getVersionToColorMap = (versionsMap: VersionsMap) => {
4783
};
4884
});
4985

86+
const colors = getColors();
87+
5088
const versionToColor: VersionToColorMap = new Map();
5189
// not every version is colored, therefore iteration index can't be used consistently
5290
// init with the colors length to put increment right after condition for better readability
53-
let currentColorIndex = COLORS.length - 1;
91+
let currentColorIndex = colors.length - 1;
5492

5593
clustersVersions
5694
// ascending by version name, just for consistency
5795
// sorting only impacts color choose for a version
5896
.sort((a, b) => a.hash - b.hash)
5997
.forEach((item) => {
6098
if (/^(\w+-)?stable/.test(item.version)) {
61-
currentColorIndex = (currentColorIndex + 1) % COLORS.length;
99+
currentColorIndex = (currentColorIndex + 1) % colors.length;
62100

63-
versionToColor.set(item.version, COLORS[currentColorIndex]);
101+
// Use fisrt color for major
102+
versionToColor.set(item.version, colors[currentColorIndex][0]);
64103

65104
const minors = Array.from(versionsMap.get(item.version) || [])
66105
.filter((v) => v !== item.version)
@@ -78,14 +117,12 @@ export const getVersionToColorMap = (versionsMap: VersionsMap) => {
78117
// so the newer version gets the brighter color
79118
.sort((a, b) => b.hash - a.hash)
80119
.forEach((minor, minorIndex) => {
81-
const majorColor = COLORS[currentColorIndex];
82-
const opacityPercent = Math.max(
83-
100 - minorIndex * (100 / minorQuantity),
84-
20,
120+
const minorColorVariant = getMinorVersionColorVariant(
121+
minorIndex,
122+
minorQuantity,
85123
);
86-
const hexOpacity = Math.round((opacityPercent * 255) / 100).toString(16);
87-
const versionColor = `${majorColor}${hexOpacity}`;
88-
versionToColor.set(minor.version, versionColor);
124+
const minorColor = colors[currentColorIndex][minorColorVariant];
125+
versionToColor.set(minor.version, minorColor);
89126
});
90127
} else {
91128
versionToColor.set(item.version, DEFAULT_COLOR);

0 commit comments

Comments
 (0)