From 348a6bf70d0f4766e57f0a3d0425b9222feccf62 Mon Sep 17 00:00:00 2001 From: silverwind <me@silverwind.io> Date: Sun, 9 Jul 2023 13:06:13 +0200 Subject: [PATCH] Always pass 6-digit hex color to monaco (#25780) (#25782) Backport https://github.com/go-gitea/gitea/pull/25780, clean cherry-pick. Monaco can not deal with color formats other than 6-digit hex, so we convert the colors for it via new [`tinycolor2`](https://github.com/bgrins/TinyColor) dependency (5kB minzipped). Also, with the addition of the module, we can replace the existing `hexToRGBColor` usage, I verified it is compatible with the current tests before removing the function. Fixes: https://github.com/go-gitea/gitea/issues/25770 --- package-lock.json | 6 +++++ package.json | 1 + web_src/js/components/ContextPopup.vue | 5 ++-- web_src/js/features/codeeditor.js | 36 ++++++++++++++------------ web_src/js/features/repo-projects.js | 5 ++-- web_src/js/utils/color.js | 21 --------------- web_src/js/utils/color.test.js | 14 +--------- 7 files changed, 33 insertions(+), 55 deletions(-) diff --git a/package-lock.json b/package-lock.json index d19195e372..a10225b336 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,6 +42,7 @@ "sortablejs": "1.15.0", "swagger-ui-dist": "5.0.0", "throttle-debounce": "5.0.0", + "tinycolor2": "1.6.0", "tippy.js": "6.3.7", "tributejs": "5.1.3", "uint8-to-base64": "0.2.0", @@ -10085,6 +10086,11 @@ "integrity": "sha512-kRwSG8Zx4tjF9ZiyH4bhaebu+EDz1BOx9hOigYHlUW4xxI/wKIUQUqo018UlU4ar6ATPBsaMrdbKZ+tmPdohFA==", "dev": true }, + "node_modules/tinycolor2": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", + "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==" + }, "node_modules/tinypool": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.5.0.tgz", diff --git a/package.json b/package.json index 08c54c27c7..fe3f0691a9 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "sortablejs": "1.15.0", "swagger-ui-dist": "5.0.0", "throttle-debounce": "5.0.0", + "tinycolor2": "1.6.0", "tippy.js": "6.3.7", "tributejs": "5.1.3", "uint8-to-base64": "0.2.0", diff --git a/web_src/js/components/ContextPopup.vue b/web_src/js/components/ContextPopup.vue index 420c271fcc..b6852655f6 100644 --- a/web_src/js/components/ContextPopup.vue +++ b/web_src/js/components/ContextPopup.vue @@ -26,7 +26,8 @@ <script> import $ from 'jquery'; import {SvgIcon} from '../svg.js'; -import {useLightTextOnBackground, hexToRGBColor} from '../utils/color.js'; +import {useLightTextOnBackground} from '../utils/color.js'; +import tinycolor from 'tinycolor2'; const {appSubUrl, i18n} = window.config; @@ -77,7 +78,7 @@ export default { labels() { return this.issue.labels.map((label) => { let textColor; - const [r, g, b] = hexToRGBColor(label.color); + const {r, g, b} = tinycolor(label.color).toRgb(); if (useLightTextOnBackground(r, g, b)) { textColor = '#eeeeee'; } else { diff --git a/web_src/js/features/codeeditor.js b/web_src/js/features/codeeditor.js index 76eeaa9898..7dbbcd3dd6 100644 --- a/web_src/js/features/codeeditor.js +++ b/web_src/js/features/codeeditor.js @@ -1,3 +1,4 @@ +import tinycolor from 'tinycolor2'; import {basename, extname, isObject, isDarkTheme} from '../utils.js'; import {onInputDebounce} from '../utils/dom.js'; @@ -69,33 +70,34 @@ export async function createMonaco(textarea, filename, editorOpts) { textarea.parentNode.append(container); // https://github.com/microsoft/monaco-editor/issues/2427 + // also, monaco can only parse 6-digit hex colors, so we convert the colors to that format const styles = window.getComputedStyle(document.documentElement); - const getProp = (name) => styles.getPropertyValue(name).trim(); + const getColor = (name) => tinycolor(styles.getPropertyValue(name).trim()).toString('hex6'); monaco.editor.defineTheme('gitea', { base: isDarkTheme() ? 'vs-dark' : 'vs', inherit: true, rules: [ { - background: getProp('--color-code-bg'), + background: getColor('--color-code-bg'), } ], colors: { - 'editor.background': getProp('--color-code-bg'), - 'editor.foreground': getProp('--color-text'), - 'editor.inactiveSelectionBackground': getProp('--color-primary-light-4'), - 'editor.lineHighlightBackground': getProp('--color-editor-line-highlight'), - 'editor.selectionBackground': getProp('--color-primary-light-3'), - 'editor.selectionForeground': getProp('--color-primary-light-3'), - 'editorLineNumber.background': getProp('--color-code-bg'), - 'editorLineNumber.foreground': getProp('--color-secondary-dark-6'), - 'editorWidget.background': getProp('--color-body'), - 'editorWidget.border': getProp('--color-secondary'), - 'input.background': getProp('--color-input-background'), - 'input.border': getProp('--color-input-border'), - 'input.foreground': getProp('--color-input-text'), - 'scrollbar.shadow': getProp('--color-shadow'), - 'progressBar.background': getProp('--color-primary'), + 'editor.background': getColor('--color-code-bg'), + 'editor.foreground': getColor('--color-text'), + 'editor.inactiveSelectionBackground': getColor('--color-primary-light-4'), + 'editor.lineHighlightBackground': getColor('--color-editor-line-highlight'), + 'editor.selectionBackground': getColor('--color-primary-light-3'), + 'editor.selectionForeground': getColor('--color-primary-light-3'), + 'editorLineNumber.background': getColor('--color-code-bg'), + 'editorLineNumber.foreground': getColor('--color-secondary-dark-6'), + 'editorWidget.background': getColor('--color-body'), + 'editorWidget.border': getColor('--color-secondary'), + 'input.background': getColor('--color-input-background'), + 'input.border': getColor('--color-input-border'), + 'input.foreground': getColor('--color-input-text'), + 'scrollbar.shadow': getColor('--color-shadow'), + 'progressBar.background': getColor('--color-primary'), } }); diff --git a/web_src/js/features/repo-projects.js b/web_src/js/features/repo-projects.js index b8cb651f69..1f1a03f078 100644 --- a/web_src/js/features/repo-projects.js +++ b/web_src/js/features/repo-projects.js @@ -1,5 +1,6 @@ import $ from 'jquery'; -import {useLightTextOnBackground, hexToRGBColor} from '../utils/color.js'; +import {useLightTextOnBackground} from '../utils/color.js'; +import tinycolor from 'tinycolor2'; const {csrfToken} = window.config; @@ -190,7 +191,7 @@ export function initRepoProject() { } function setLabelColor(label, color) { - const [r, g, b] = hexToRGBColor(color); + const {r, g, b} = tinycolor(color).toRgb(); if (useLightTextOnBackground(r, g, b)) { label.removeClass('dark-label').addClass('light-label'); } else { diff --git a/web_src/js/utils/color.js b/web_src/js/utils/color.js index 389e2d095f..5d9c4ca45d 100644 --- a/web_src/js/utils/color.js +++ b/web_src/js/utils/color.js @@ -13,27 +13,6 @@ function getLuminance(r, g, b) { return 0.2126 * R + 0.7152 * G + 0.0722 * B; } -// Get color as RGB values in 0..255 range from the hex color string (with or without #) -export function hexToRGBColor(backgroundColorStr) { - let backgroundColor = backgroundColorStr; - if (backgroundColorStr[0] === '#') { - backgroundColor = backgroundColorStr.substring(1); - } - // only support transfer of rgb, rgba, rrggbb and rrggbbaa - // if not in these formats, use default values 0, 0, 0 - if (![3, 4, 6, 8].includes(backgroundColor.length)) { - return [0, 0, 0]; - } - if ([3, 4].includes(backgroundColor.length)) { - const [r, g, b] = backgroundColor; - backgroundColor = `${r}${r}${g}${g}${b}${b}`; - } - const r = parseInt(backgroundColor.substring(0, 2), 16); - const g = parseInt(backgroundColor.substring(2, 4), 16); - const b = parseInt(backgroundColor.substring(4, 6), 16); - return [r, g, b]; -} - // Reference from: https://firsching.ch/github_labels.html // In the future WCAG 3 APCA may be a better solution. // Check if text should use light color based on RGB of background diff --git a/web_src/js/utils/color.test.js b/web_src/js/utils/color.test.js index 592e93b0f2..7d45d191a0 100644 --- a/web_src/js/utils/color.test.js +++ b/web_src/js/utils/color.test.js @@ -1,17 +1,5 @@ import {test, expect} from 'vitest'; -import {hexToRGBColor, useLightTextOnBackground} from './color.js'; - -test('hexToRGBColor', () => { - expect(hexToRGBColor('2b8685')).toEqual([43, 134, 133]); - expect(hexToRGBColor('1e1')).toEqual([17, 238, 17]); - expect(hexToRGBColor('#1e1')).toEqual([17, 238, 17]); - expect(hexToRGBColor('1e16')).toEqual([17, 238, 17]); - expect(hexToRGBColor('3bb6b3')).toEqual([59, 182, 179]); - expect(hexToRGBColor('#3bb6b399')).toEqual([59, 182, 179]); - expect(hexToRGBColor('#0')).toEqual([0, 0, 0]); - expect(hexToRGBColor('#00000')).toEqual([0, 0, 0]); - expect(hexToRGBColor('#1234567')).toEqual([0, 0, 0]); -}); +import {useLightTextOnBackground} from './color.js'; test('useLightTextOnBackground', () => { expect(useLightTextOnBackground(215, 58, 74)).toBe(true);