From 7e5707ac2a3ee200b046762439fa1b3b8ff1b7ab Mon Sep 17 00:00:00 2001 From: mufazalov Date: Wed, 2 Jul 2025 14:54:32 +0300 Subject: [PATCH 1/2] feat: update versions colors --- src/containers/Versions/Versions.tsx | 2 +- src/utils/clusterVersionColors.ts | 25 +++++-- src/utils/index.ts | 18 +++++ src/utils/versions/getVersionsColors.ts | 91 ++++++++++++++++++------- 4 files changed, 103 insertions(+), 33 deletions(-) diff --git a/src/containers/Versions/Versions.tsx b/src/containers/Versions/Versions.tsx index 417a7feef..7e0042e89 100644 --- a/src/containers/Versions/Versions.tsx +++ b/src/containers/Versions/Versions.tsx @@ -32,7 +32,7 @@ export function VersionsContainer({cluster, loading}: VersionsContainerProps) { {tablets: false, fieldsRequired: ['SystemState', 'SubDomainKey']}, {pollingInterval: autoRefreshInterval}, ); - const versionToColor = useVersionToColorMap(); + const versionToColor = useVersionToColorMap(cluster); const versionsValues = useGetVersionValues({cluster, versionToColor, clusterLoading: loading}); diff --git a/src/utils/clusterVersionColors.ts b/src/utils/clusterVersionColors.ts index a97c17379..deab406dd 100644 --- a/src/utils/clusterVersionColors.ts +++ b/src/utils/clusterVersionColors.ts @@ -3,7 +3,13 @@ import uniqBy from 'lodash/uniqBy'; import type {MetaClusterVersion} from '../types/api/meta'; import type {VersionToColorMap} from '../types/versions'; -import {COLORS, DEFAULT_COLOR, getMinorVersion, hashCode} from './versions'; +import { + DEFAULT_COLOR, + getColors, + getMinorVersion, + getMinorVersionColorVariant, + hashCode, +} from './versions'; const UNDEFINED_COLOR_INDEX = '__no_color__'; @@ -28,6 +34,8 @@ export const getVersionMap = ( export const getVersionColors = (versionMap: VersionsMap) => { const versionToColor: VersionToColorMap = new Map(); + const colors = getColors(); + for (const [baseColorIndex, item] of versionMap) { Array.from(item) // descending by version name: newer versions come first, @@ -38,13 +46,16 @@ export const getVersionColors = (versionMap: VersionsMap) => { versionToColor.set(minor, DEFAULT_COLOR); } else { // baseColorIndex is numeric as we check if it is UNDEFINED_COLOR_INDEX before - const currentColorIndex = Number(baseColorIndex) % COLORS.length; + const currentColorIndex = Number(baseColorIndex) % colors.length; const minorQuantity = item.size; - const majorColor = COLORS[currentColorIndex]; - const opacityPercent = Math.max(100 - minorIndex * (100 / minorQuantity), 20); - const hexOpacity = Math.round((opacityPercent * 255) / 100).toString(16); - const versionColor = `${majorColor}${hexOpacity}`; - versionToColor.set(minor, versionColor); + + const minorColorVariant = getMinorVersionColorVariant( + minorIndex, + minorQuantity, + ); + const minorColor = colors[currentColorIndex][minorColorVariant]; + + versionToColor.set(minor, minorColor); } }); } diff --git a/src/utils/index.ts b/src/utils/index.ts index 8de8c148c..980c41205 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -17,3 +17,21 @@ export function normalizePathSlashes(path: string) { // (? { }, 0); }; -// TODO: colors used in charts as well, need to move to constants -// 11 distinct colors from https://mokole.com/palette.html -export const COLORS = [ - '#008000', // green - '#4169e1', // royalblue - '#ffd700', // gold - '#ff8c00', // darkorange - '#808000', // olive - '#e9967a', // darksalmon - '#ff1493', // deeppink - '#00bfff', // deepskyblue - '#da70d6', // orchid - '#8b4513', //saddlebrown - '#b22222', // firebrick +const DARK_COLORS = [ + ['#D50C38', '#FF2051', '#FB3A64', '#FF6989'], + ['#EB3320', '#FF503E', '#FF8376', '#FFA399'], + ['#F47B10', '#FF9B43', '#FFB06A', '#FFC693'], + ['#FFEA00', '#FFEE31', '#FFF480', '#FFF8A9'], + ['#83D400', '#B1FF33', '#CBFF78', '#DDFFA7'], + ['#27C98B', '#16FFA6', '#4CFFBA', '#9BFFD8'], + ['#0EDBDE', '#0CFBFF', '#63FDFF', '#B1FEFF'], + ['#2059FF', '#4070FF', '#658BFF', '#A1B9FF'], + ['#AB07E3', '#C92CFF', '#DD78FF', '#E79FFF'], + ['#E71498', '#FF34B3', '#FF75CB', '#FFB0E1'], ]; -export const DEFAULT_COLOR = '#3cb371'; // mediumseagreen +const LIGHT_COLORS = [ + ['#F4315B', '#FF426B', '#FF7391', '#FF8BA4'], + ['#FF6050', '#FF7A6D', '#FFAFA6', '#FFBCB5'], + ['#FF9233', '#FFAD65', '#FFC593', '#FFD3AC'], + ['#FFEA00', '#FFEE31', '#FFF480', '#FFF8A9'], + ['#A1EE26', '#B1FF33', '#CBFF78', '#DDFFA7'], + ['#31EBA4', '#16FFA6', '#4CFFBA', '#9BFFD8'], + ['#2EE4E8', '#0CFBFF', '#63FDFF', '#B1FEFF'], + ['#386BFF', '#4070FF', '#658BFF', '#A1B9FF'], + ['#C73AF7', '#C92CFF', '#DD78FF', '#E79FFF'], + ['#FF49BB', '#FF34B3', '#FF75CB', '#FFB0E1'], +]; + +export function getColors() { + return getTheme() === 'dark' ? DARK_COLORS : LIGHT_COLORS; +} + +/** Calculates sub color index */ +export function getMinorVersionColorVariant(minorIndex: number, minorQuantity: number) { + // We have 4 sub colors for each color + // For 4+ minors first 25% will be colored with the first most bright color + // Every next 25% will be colored with corresponding color + // Do not use all colors if there are less than 4 minors + + if (minorQuantity === 1) { + return 0; + } + // Use only 2 colors + if (minorQuantity === 2) { + return Math.floor((2 * minorIndex) / minorQuantity); + } + // Use only 3 colors + if (minorQuantity === 3) { + return Math.floor((3 * minorIndex) / minorQuantity); + } + + // Max minor index is minorQuantity - 1 + // So result values always will be in range from 0 to 3 + return Math.floor((4 * minorIndex) / minorQuantity); +} + +// TODO: replace with color suggested by designer +export const DEFAULT_COLOR = 'saddlebrown'; export const getVersionsMap = (versions: string[], initialMap: VersionsMap = new Map()) => { versions.forEach((version) => { @@ -47,10 +87,12 @@ export const getVersionToColorMap = (versionsMap: VersionsMap) => { }; }); + const colors = getColors(); + const versionToColor: VersionToColorMap = new Map(); // not every version is colored, therefore iteration index can't be used consistently // init with the colors length to put increment right after condition for better readability - let currentColorIndex = COLORS.length - 1; + let currentColorIndex = colors.length - 1; clustersVersions // ascending by version name, just for consistency @@ -58,9 +100,10 @@ export const getVersionToColorMap = (versionsMap: VersionsMap) => { .sort((a, b) => a.hash - b.hash) .forEach((item) => { if (/^(\w+-)?stable/.test(item.version)) { - currentColorIndex = (currentColorIndex + 1) % COLORS.length; + currentColorIndex = (currentColorIndex + 1) % colors.length; - versionToColor.set(item.version, COLORS[currentColorIndex]); + // Use fisrt color for major + versionToColor.set(item.version, colors[currentColorIndex][0]); const minors = Array.from(versionsMap.get(item.version) || []) .filter((v) => v !== item.version) @@ -78,14 +121,12 @@ export const getVersionToColorMap = (versionsMap: VersionsMap) => { // so the newer version gets the brighter color .sort((a, b) => b.hash - a.hash) .forEach((minor, minorIndex) => { - const majorColor = COLORS[currentColorIndex]; - const opacityPercent = Math.max( - 100 - minorIndex * (100 / minorQuantity), - 20, + const minorColorVariant = getMinorVersionColorVariant( + minorIndex, + minorQuantity, ); - const hexOpacity = Math.round((opacityPercent * 255) / 100).toString(16); - const versionColor = `${majorColor}${hexOpacity}`; - versionToColor.set(minor.version, versionColor); + const minorColor = colors[currentColorIndex][minorColorVariant]; + versionToColor.set(minor.version, minorColor); }); } else { versionToColor.set(item.version, DEFAULT_COLOR); From e48c40de964340a1af8620848256e5cf155d76f3 Mon Sep 17 00:00:00 2001 From: mufazalov Date: Wed, 2 Jul 2025 17:49:14 +0300 Subject: [PATCH 2/2] use css vars for colors for proper theme switch --- src/styles/index.scss | 1 + src/styles/versions.scss | 106 ++++++++++++++++++++++++ src/utils/clusterVersionColors.ts | 8 +- src/utils/index.ts | 18 ---- src/utils/versions/getVersionsColors.ts | 103 ++++++++++++++--------- 5 files changed, 176 insertions(+), 60 deletions(-) create mode 100644 src/styles/versions.scss diff --git a/src/styles/index.scss b/src/styles/index.scss index 75de0026c..9ae0d76a0 100644 --- a/src/styles/index.scss +++ b/src/styles/index.scss @@ -2,6 +2,7 @@ @forward './themes.scss'; @forward './unipika.scss'; @forward './illustrations.scss'; +@forward './versions.scss'; body { --ydb-drawer-veil-z-index: 2; diff --git a/src/styles/versions.scss b/src/styles/versions.scss new file mode 100644 index 000000000..14b1c1371 --- /dev/null +++ b/src/styles/versions.scss @@ -0,0 +1,106 @@ +.g-root { + &_theme_light, + &_theme_light-hc { + --versions-red-1: #f4315b; + --versions-red-2: #ff426b; + --versions-red-3: #ff7391; + --versions-red-4: #ff8ba4; + + --versions-orange-red-1: #ff6050; + --versions-orange-red-2: #ff7a6d; + --versions-orange-red-3: #ffafa6; + --versions-orange-red-4: #ffbcb5; + + --versions-orange-1: #ff9233; + --versions-orange-2: #ffad65; + --versions-orange-3: #ffc593; + --versions-orange-4: #ffd3ac; + + --versions-yellow-1: #ffea00; + --versions-yellow-2: #ffee31; + --versions-yellow-3: #fff480; + --versions-yellow-4: #fff8a9; + + --versions-green-1: #a1ee26; + --versions-green-2: #b1ff33; + --versions-green-3: #cbff78; + --versions-green-4: #ddffa7; + + --versions-teal-1: #31eba4; + --versions-teal-2: #16ffa6; + --versions-teal-3: #4cffba; + --versions-teal-4: #9bffd8; + + --versions-cyan-1: #2ee4e8; + --versions-cyan-2: #0cfbff; + --versions-cyan-3: #63fdff; + --versions-cyan-4: #b1feff; + + --versions-blue-1: #386bff; + --versions-blue-2: #4070ff; + --versions-blue-3: #658bff; + --versions-blue-4: #a1b9ff; + + --versions-purple-1: #c73af7; + --versions-purple-2: #c92cff; + --versions-purple-3: #dd78ff; + --versions-purple-4: #e79fff; + + --versions-pink-1: #ff49bb; + --versions-pink-2: #ff34b3; + --versions-pink-3: #ff75cb; + --versions-pink-4: #ffb0e1; + } + &_theme_dark, + &_theme_dark-hc { + --versions-red-1: #d50c38; + --versions-red-2: #ff2051; + --versions-red-3: #fb3a64; + --versions-red-4: #ff6989; + + --versions-orange-red-1: #eb3320; + --versions-orange-red-2: #ff503e; + --versions-orange-red-3: #ff8376; + --versions-orange-red-4: #ffa399; + + --versions-orange-1: #f47b10; + --versions-orange-2: #ff9b43; + --versions-orange-3: #ffb06a; + --versions-orange-4: #ffc693; + + --versions-yellow-1: #ffea00; + --versions-yellow-2: #ffee31; + --versions-yellow-3: #fff480; + --versions-yellow-4: #fff8a9; + + --versions-green-1: #83d400; + --versions-green-2: #b1ff33; + --versions-green-3: #cbff78; + --versions-green-4: #ddffa7; + + --versions-teal-1: #27c98b; + --versions-teal-2: #16ffa6; + --versions-teal-3: #4cffba; + --versions-teal-4: #9bffd8; + + --versions-cyan-1: #0edbde; + --versions-cyan-2: #0cfbff; + --versions-cyan-3: #63fdff; + --versions-cyan-4: #b1feff; + + --versions-blue-1: #2059ff; + --versions-blue-2: #4070ff; + --versions-blue-3: #658bff; + --versions-blue-4: #a1b9ff; + + --versions-purple-1: #ab07e3; + --versions-purple-2: #c92cff; + --versions-purple-3: #dd78ff; + --versions-purple-4: #e79fff; + + --versions-pink-1: #e71498; + --versions-pink-2: #ff34b3; + --versions-pink-3: #ff75cb; + --versions-pink-4: #ffb0e1; + } +} diff --git a/src/utils/clusterVersionColors.ts b/src/utils/clusterVersionColors.ts index deab406dd..0a88ed78e 100644 --- a/src/utils/clusterVersionColors.ts +++ b/src/utils/clusterVersionColors.ts @@ -4,8 +4,8 @@ import type {MetaClusterVersion} from '../types/api/meta'; import type {VersionToColorMap} from '../types/versions'; import { + COLORS, DEFAULT_COLOR, - getColors, getMinorVersion, getMinorVersionColorVariant, hashCode, @@ -34,8 +34,6 @@ export const getVersionMap = ( export const getVersionColors = (versionMap: VersionsMap) => { const versionToColor: VersionToColorMap = new Map(); - const colors = getColors(); - for (const [baseColorIndex, item] of versionMap) { Array.from(item) // descending by version name: newer versions come first, @@ -46,14 +44,14 @@ export const getVersionColors = (versionMap: VersionsMap) => { versionToColor.set(minor, DEFAULT_COLOR); } else { // baseColorIndex is numeric as we check if it is UNDEFINED_COLOR_INDEX before - const currentColorIndex = Number(baseColorIndex) % colors.length; + const currentColorIndex = Number(baseColorIndex) % COLORS.length; const minorQuantity = item.size; const minorColorVariant = getMinorVersionColorVariant( minorIndex, minorQuantity, ); - const minorColor = colors[currentColorIndex][minorColorVariant]; + const minorColor = COLORS[currentColorIndex][minorColorVariant]; versionToColor.set(minor, minorColor); } diff --git a/src/utils/index.ts b/src/utils/index.ts index 980c41205..8de8c148c 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -17,21 +17,3 @@ export function normalizePathSlashes(path: string) { // (? { }, 0); }; -const DARK_COLORS = [ - ['#D50C38', '#FF2051', '#FB3A64', '#FF6989'], - ['#EB3320', '#FF503E', '#FF8376', '#FFA399'], - ['#F47B10', '#FF9B43', '#FFB06A', '#FFC693'], - ['#FFEA00', '#FFEE31', '#FFF480', '#FFF8A9'], - ['#83D400', '#B1FF33', '#CBFF78', '#DDFFA7'], - ['#27C98B', '#16FFA6', '#4CFFBA', '#9BFFD8'], - ['#0EDBDE', '#0CFBFF', '#63FDFF', '#B1FEFF'], - ['#2059FF', '#4070FF', '#658BFF', '#A1B9FF'], - ['#AB07E3', '#C92CFF', '#DD78FF', '#E79FFF'], - ['#E71498', '#FF34B3', '#FF75CB', '#FFB0E1'], +export const COLORS = [ + [ + 'var(--versions-red-1)', + 'var(--versions-red-2)', + 'var(--versions-red-3)', + 'var(--versions-red-4)', + ], + [ + 'var(--versions-orange-red-1)', + 'var(--versions-orange-red-2)', + 'var(--versions-orange-red-3)', + 'var(--versions-orange-red-4)', + ], + [ + 'var(--versions-orange-1)', + 'var(--versions-orange-2)', + 'var(--versions-orange-3)', + 'var(--versions-orange-4)', + ], + [ + 'var(--versions-yellow-1)', + 'var(--versions-yellow-2)', + 'var(--versions-yellow-3)', + 'var(--versions-yellow-4)', + ], + [ + 'var(--versions-green-1)', + 'var(--versions-green-2)', + 'var(--versions-green-3)', + 'var(--versions-green-4)', + ], + [ + 'var(--versions-teal-1)', + 'var(--versions-teal-2)', + 'var(--versions-teal-3)', + 'var(--versions-teal-4)', + ], + [ + 'var(--versions-cyan-1)', + 'var(--versions-cyan-2)', + 'var(--versions-cyan-3)', + 'var(--versions-cyan-4)', + ], + [ + 'var(--versions-blue-1)', + 'var(--versions-blue-2)', + 'var(--versions-blue-3)', + 'var(--versions-blue-4)', + ], + [ + 'var(--versions-purple-1)', + 'var(--versions-purple-2)', + 'var(--versions-purple-3)', + 'var(--versions-purple-4)', + ], + [ + 'var(--versions-pink-1)', + 'var(--versions-pink-2)', + 'var(--versions-pink-3)', + 'var(--versions-pink-4)', + ], ]; -const LIGHT_COLORS = [ - ['#F4315B', '#FF426B', '#FF7391', '#FF8BA4'], - ['#FF6050', '#FF7A6D', '#FFAFA6', '#FFBCB5'], - ['#FF9233', '#FFAD65', '#FFC593', '#FFD3AC'], - ['#FFEA00', '#FFEE31', '#FFF480', '#FFF8A9'], - ['#A1EE26', '#B1FF33', '#CBFF78', '#DDFFA7'], - ['#31EBA4', '#16FFA6', '#4CFFBA', '#9BFFD8'], - ['#2EE4E8', '#0CFBFF', '#63FDFF', '#B1FEFF'], - ['#386BFF', '#4070FF', '#658BFF', '#A1B9FF'], - ['#C73AF7', '#C92CFF', '#DD78FF', '#E79FFF'], - ['#FF49BB', '#FF34B3', '#FF75CB', '#FFB0E1'], -]; - -export function getColors() { - return getTheme() === 'dark' ? DARK_COLORS : LIGHT_COLORS; -} +export const DEFAULT_COLOR = 'var(--g-color-base-generic-medium)'; /** Calculates sub color index */ export function getMinorVersionColorVariant(minorIndex: number, minorQuantity: number) { @@ -64,9 +98,6 @@ export function getMinorVersionColorVariant(minorIndex: number, minorQuantity: n return Math.floor((4 * minorIndex) / minorQuantity); } -// TODO: replace with color suggested by designer -export const DEFAULT_COLOR = 'saddlebrown'; - export const getVersionsMap = (versions: string[], initialMap: VersionsMap = new Map()) => { versions.forEach((version) => { const majorVersion = getMajorVersion(version); @@ -87,12 +118,10 @@ export const getVersionToColorMap = (versionsMap: VersionsMap) => { }; }); - const colors = getColors(); - const versionToColor: VersionToColorMap = new Map(); // not every version is colored, therefore iteration index can't be used consistently // init with the colors length to put increment right after condition for better readability - let currentColorIndex = colors.length - 1; + let currentColorIndex = COLORS.length - 1; clustersVersions // ascending by version name, just for consistency @@ -100,10 +129,10 @@ export const getVersionToColorMap = (versionsMap: VersionsMap) => { .sort((a, b) => a.hash - b.hash) .forEach((item) => { if (/^(\w+-)?stable/.test(item.version)) { - currentColorIndex = (currentColorIndex + 1) % colors.length; + currentColorIndex = (currentColorIndex + 1) % COLORS.length; // Use fisrt color for major - versionToColor.set(item.version, colors[currentColorIndex][0]); + versionToColor.set(item.version, COLORS[currentColorIndex][0]); const minors = Array.from(versionsMap.get(item.version) || []) .filter((v) => v !== item.version) @@ -125,7 +154,7 @@ export const getVersionToColorMap = (versionsMap: VersionsMap) => { minorIndex, minorQuantity, ); - const minorColor = colors[currentColorIndex][minorColorVariant]; + const minorColor = COLORS[currentColorIndex][minorColorVariant]; versionToColor.set(minor.version, minorColor); }); } else {