diff --git a/apps/client/package.json b/apps/client/package.json index 1db8353e7..06c605f74 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -21,7 +21,6 @@ "@tanstack/react-table": "^8.21.3", "autosize": "^6.0.1", "axios": "^1.9.0", - "color": "^4.2.3", "csv-stringify": "^6.4.5", "framer-motion": "^10.10.0", "prismjs": "^1.29.0", @@ -67,7 +66,6 @@ "devDependencies": { "@sentry/vite-plugin": "^2.16.1", "@tanstack/eslint-plugin-query": "^5.8.4", - "@types/color": "^3.0.3", "@types/prismjs": "^1.26.5", "@types/react": "^18.0.26", "@types/react-dom": "^18.0.10", diff --git a/apps/client/src/common/utils/__tests__/styleUtils.test.ts b/apps/client/src/common/utils/__tests__/styleUtils.test.ts index f5d753759..f1c532082 100644 --- a/apps/client/src/common/utils/__tests__/styleUtils.test.ts +++ b/apps/client/src/common/utils/__tests__/styleUtils.test.ts @@ -18,19 +18,19 @@ describe('getAccessibleColour()', () => { it('handles named colours', () => { const colour = 'red'; const { backgroundColor, color } = getAccessibleColour(colour); - expect(backgroundColor).toBe('#FF0000FF'); + expect(backgroundColor).toBe('#ff0000ff'); expect(color).toBe('#fffffa'); }); it('handles hex colours', () => { const colour = '#0F0'; const { backgroundColor, color } = getAccessibleColour(colour); - expect(backgroundColor).toBe('#00FF00FF'); + expect(backgroundColor).toBe('#00ff00ff'); expect(color).toBe('black'); }); it('handles transparens', () => { const colour = '#0F08'; const { backgroundColor, color } = getAccessibleColour(colour); - expect(backgroundColor).toBe('#0C940CFF'); + expect(backgroundColor).toBe('#0c940cff'); expect(color).toBe('#fffffa'); }); }); diff --git a/apps/client/src/common/utils/styleUtils.ts b/apps/client/src/common/utils/styleUtils.ts index 3c3c331e5..7a72c4d18 100644 --- a/apps/client/src/common/utils/styleUtils.ts +++ b/apps/client/src/common/utils/styleUtils.ts @@ -1,27 +1,27 @@ -import Color from 'color'; +import { RGBColour } from 'ontime-types'; +import { colourToHex, cssOrHexToColour, isLightColour, mixColours } from 'ontime-utils'; type ColourCombination = { backgroundColor: string; color: string; }; +const defaultUiBackground: RGBColour = { red: 26, green: 26, blue: 26, alpha: 1 }; /** * @description Selects text colour to maintain accessible contrast * @param bgColour * @return {{backgroundColor, color: string}} */ export const getAccessibleColour = (bgColour?: string): ColourCombination => { - if (bgColour) { - try { - const originalColour = Color(bgColour); - const backgroundColorMix = originalColour.alpha(1).mix(Color('#1a1a1a'), 1 - originalColour.alpha()); - const textColor = backgroundColorMix.isLight() ? 'black' : '#fffffa'; - return { backgroundColor: backgroundColorMix.hexa(), color: textColor }; - } catch (_error) { - /* we do not handle errors here */ - } - } - return { backgroundColor: '#1a1a1a', color: '#fffffa' }; + if (!bgColour) return { backgroundColor: '#1a1a1a', color: '#fffffa' }; + + const originalColour = cssOrHexToColour(bgColour); + if (!originalColour) return { backgroundColor: '#1a1a1a', color: '#fffffa' }; + + const backgroundColorMix = mixColours(defaultUiBackground, originalColour, 1 - originalColour.alpha); + const textColor = isLightColour(backgroundColorMix) ? 'black' : '#fffffa'; + + return { backgroundColor: colourToHex(backgroundColorMix), color: textColor }; }; /** @@ -39,11 +39,8 @@ export const timerPlaceholderMin = '––:––'; * Adds opacity to a given colour if possible */ export function alpha(colour: string, amount: number): string { - try { - const withAlpha = Color(colour).alpha(amount).hexa(); - return withAlpha; - } catch (_error) { - /* we do not handle errors here */ - } - return colour; + const originalColour = cssOrHexToColour(colour); + if (!originalColour) return colour; + originalColour.alpha = amount; + return colourToHex(originalColour); } diff --git a/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/CuesheetBody.tsx b/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/CuesheetBody.tsx index e4d722b1b..43e6c56d2 100644 --- a/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/CuesheetBody.tsx +++ b/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/CuesheetBody.tsx @@ -1,7 +1,7 @@ import { MutableRefObject } from 'react'; import { RowModel, Table } from '@tanstack/react-table'; -import Color from 'color'; import { isOntimeBlock, isOntimeDelay, isOntimeEvent, OntimeEntry } from 'ontime-types'; +import { colourToHex, cssOrHexToColour } from 'ontime-utils'; import { useSelectedEventId } from '../../../../common/hooks/useSocket'; import { lazyEvaluate } from '../../../../common/utils/lazyEvaluate'; @@ -76,12 +76,13 @@ export default function CuesheetBody(props: CuesheetBodyProps) { if (isSelected) { rowBgColour = '#D20300'; // $red-700 } else if (entry.colour) { - try { - // the colour is user defined and might be invalid - const accessibleBackgroundColor = Color(getAccessibleColour(entry.colour).backgroundColor); - rowBgColour = accessibleBackgroundColor.fade(0.75).hexa(); - } catch (_error) { - /* we do not handle errors here */ + // the colour is user defined and might be invalid + const accessibleBackgroundColor = cssOrHexToColour(getAccessibleColour(entry.colour).backgroundColor); + if (accessibleBackgroundColor !== null) { + rowBgColour = colourToHex({ + ...accessibleBackgroundColor, + alpha: accessibleBackgroundColor.alpha * 0.25, + }); } } diff --git a/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/EventRow.tsx b/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/EventRow.tsx index 5e67bba42..e0cf99180 100644 --- a/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/EventRow.tsx +++ b/apps/client/src/views/cuesheet/cuesheet-table/cuesheet-table-elements/EventRow.tsx @@ -1,8 +1,8 @@ import { memo, MutableRefObject, useLayoutEffect, useRef, useState } from 'react'; import { IoEllipsisHorizontal } from 'react-icons/io5'; import { flexRender, Table } from '@tanstack/react-table'; -import Color from 'color'; -import { OntimeEntry, OntimeEvent } from 'ontime-types'; +import { OntimeEntry, OntimeEvent, RGBColour } from 'ontime-types'; +import { colourToHex, cssOrHexToColour } from 'ontime-utils'; import IconButton from '../../../../common/components/buttons/IconButton'; import { cx, getAccessibleColour } from '../../../../common/utils/styleUtils'; @@ -75,7 +75,8 @@ function EventRow(props: EventRowProps) { }, [ownRef, selectedRef]); const { color, backgroundColor } = getAccessibleColour(event.colour); - const mutedText = Color(color).fade(0.4).hexa(); + const tmpColour = cssOrHexToColour(color) as RGBColour; // we know this to be a correct colour + const mutedText = colourToHex({ ...tmpColour, alpha: tmpColour.alpha * 0.6 }); return ( { + + const worksheets: string[] = []; + spreadsheets.data.sheets?.forEach((sheet) => { if (sheet.properties?.title) { - return sheet.properties.title; + worksheets.push(sheet.properties.title); } }); - if (!worksheets) { + if (worksheets.length === 0) { throw new Error('No worksheets found'); } - return worksheets; + return { worksheetOptions: worksheets }; } catch (error) { // attempt to catch errors caused by importing xlsx catchCommonImportXlsxError(error); @@ -293,7 +295,17 @@ async function verifyWorksheet(sheetId: string, worksheet: string): Promise<{ wo if (!selectedWorksheet) { throw new Error('Could not find worksheet'); } - if (!selectedWorksheet.properties || !selectedWorksheet.properties.sheetId) { + /* + The first spreadsheet provided by google sheet has an id = 0, + so !0 returns true, the only other number that returns true in this setup is NaN, + so if x !== 0 && x !== NaN, then !x returns false, we indeed want !NaN to return true, + but we would like !0 to return false, reason why is also checked that the id is not 0, + because if it is 0, then I should not enter the condition. + */ + if ( + !selectedWorksheet.properties || + (!selectedWorksheet.properties.sheetId && selectedWorksheet.properties.sheetId !== 0) + ) { throw new Error('Got invalid data from worksheet'); } diff --git a/apps/server/src/services/sheet-service/__tests__/sheetUtils.test.ts b/apps/server/src/services/sheet-service/__tests__/sheetUtils.test.ts index 95f8d0542..006155c26 100644 --- a/apps/server/src/services/sheet-service/__tests__/sheetUtils.test.ts +++ b/apps/server/src/services/sheet-service/__tests__/sheetUtils.test.ts @@ -274,6 +274,6 @@ describe('cellRequestFromEvent()', () => { const result2 = cellRequestFromEvent(event, 10, 1234, metadata); expect(result2.updateCells?.start?.rowIndex).toStrictEqual(21); expect(result2.updateCells?.start?.columnIndex).toStrictEqual(5); - expect(result2.updateCells?.fields).toStrictEqual('userEnteredValue'); + expect(result2.updateCells?.fields).toStrictEqual('userEnteredValue,userEnteredFormat'); }); }); diff --git a/apps/server/src/services/sheet-service/sheetUtils.ts b/apps/server/src/services/sheet-service/sheetUtils.ts index f6fb59e30..d9d27948c 100644 --- a/apps/server/src/services/sheet-service/sheetUtils.ts +++ b/apps/server/src/services/sheet-service/sheetUtils.ts @@ -1,5 +1,5 @@ -import { isOntimeBlock, isOntimeEvent, OntimeEvent, OntimeEntry } from 'ontime-types'; -import { millisToString } from 'ontime-utils'; +import { isOntimeBlock, isOntimeEvent, OntimeEvent, OntimeEntry, RGBColour } from 'ontime-types'; +import { cssOrHexToColour, isLightColour, millisToString, mixColours } from 'ontime-utils'; import type { sheets_v4 } from '@googleapis/sheets'; import { is } from '../../utils/is.js'; @@ -100,8 +100,26 @@ export function cellRequestFromEvent( } } + const colors = isOntimeEvent(event) || isOntimeBlock(event) ? getAccessibleColour(event.colour) : undefined; + const cellColor: sheets_v4.Schema$CellData = !colors + ? {} + : { + userEnteredFormat: { + backgroundColor: toSheetColourLevel(colors.background), + textFormat: { + foregroundColor: toSheetColourLevel(colors.text), + }, + borders: { + bottom: { + style: 'SOLID', + color: toSheetColourLevel(colors.border), + }, + }, + }, + }; + const returnRows: sheets_v4.Schema$CellData[] = rowData.map(([key, _]) => { - return getCellData(key, event); + return { ...getCellData(key, event), ...cellColor }; }); return { @@ -111,7 +129,7 @@ export function cellRequestFromEvent( rowIndex: index + rowData[0][1]['row'] + 1, columnIndex: titleCol, }, - fields: 'userEnteredValue', + fields: 'userEnteredValue,userEnteredFormat', rows: [ { values: returnRows, @@ -156,3 +174,29 @@ function getCellData(key: keyof OntimeEvent | 'blank', event: OntimeEntry) { return {}; } + +type googleSheetCellColour = { + background: RGBColour; + text: RGBColour; + border: RGBColour; +}; + +function getAccessibleColour(bgColour?: string): googleSheetCellColour | undefined { + if (!bgColour) return undefined; + + const background = cssOrHexToColour(bgColour); + if (!background) return undefined; + + const text = isLightColour(background) ? BLACK : WHITE; + const border = mixColours(background, text, 0.2); + + return { background, text, border }; +} + +const BLACK: RGBColour = { red: 0, green: 0, blue: 0, alpha: 1 }; +const WHITE: RGBColour = { red: 255, green: 255, blue: 255, alpha: 0.98 }; + +// sheets use color values from 0 to 1 +function toSheetColourLevel(colour: RGBColour): RGBColour { + return { red: colour.red / 255, green: colour.green / 255, blue: colour.blue / 255, alpha: colour.alpha }; +} diff --git a/apps/server/src/utils/coerceType.ts b/apps/server/src/utils/coerceType.ts index 0f64c910f..be9c68f71 100644 --- a/apps/server/src/utils/coerceType.ts +++ b/apps/server/src/utils/coerceType.ts @@ -1,4 +1,4 @@ -import { isColourHex } from 'ontime-utils'; +import { CssColours, isColourHex } from 'ontime-utils'; /** * @description Converts a value to an item in the provided enume. @@ -95,160 +95,8 @@ export function coerceColour(value: unknown): string { if (lowerCaseValue === '') { return lowerCaseValue; // None colour the same as the UI 'Ø' button } - if (!(lowerCaseValue in cssColours)) { + if (!(lowerCaseValue in CssColours)) { throw new Error('Invalid colour name received'); } return lowerCaseValue; } - -//https://developer.mozilla.org/en-US/docs/Web/CSS/named-color -const cssColours = { - aliceblue: '#f0f8ff', - antiquewhite: '#faebd7', - aqua: '#00ffff', - aquamarine: '#7fffd4', - azure: '#f0ffff', - beige: '#f5f5dc', - bisque: '#ffe4c4', - black: '#000000', - blanchedalmond: '#ffebcd', - blue: '#0000ff', - blueviolet: '#8a2be2', - brown: '#a52a2a', - burlywood: '#deb887', - cadetblue: '#5f9ea0', - chartreuse: '#7fff00', - chocolate: '#d2691e', - coral: '#ff7f50', - cornflowerblue: '#6495ed', - cornsilk: '#fff8dc', - crimson: '#dc143c', - cyan: '#00ffff', - darkblue: '#00008b', - darkcyan: '#008b8b', - darkgoldenrod: '#b8860b', - darkgray: '#a9a9a9', - darkgreen: '#006400', - darkgrey: '#a9a9a9', - darkkhaki: '#bdb76b', - darkmagenta: '#8b008b', - darkolivegreen: '#556b2f', - darkorange: '#ff8c00', - darkorchid: '#9932cc', - darkred: '#8b0000', - darksalmon: '#e9967a', - darkseagreen: '#8fbc8f', - darkslateblue: '#483d8b', - darkslategray: '#2f4f4f', - darkslategrey: '#2f4f4f', - darkturquoise: '#00ced1', - darkviolet: '#9400d3', - deeppink: '#ff1493', - deepskyblue: '#00bfff', - dimgray: '#696969', - dimgrey: '#696969', - dodgerblue: '#1e90ff', - firebrick: '#b22222', - floralwhite: '#fffaf0', - forestgreen: '#228b22', - fuchsia: '#ff00ff', - gainsboro: '#dcdcdc', - ghostwhite: '#f8f8ff', - goldenrod: '#daa520', - gold: '#ffd700', - gray: '#808080', - green: '#008000', - greenyellow: '#adff2f', - grey: '#808080', - honeydew: '#f0fff0', - hotpink: '#ff69b4', - indianred: '#cd5c5c', - indigo: '#4b0082', - ivory: '#fffff0', - khaki: '#f0e68c', - lavenderblush: '#fff0f5', - lavender: '#e6e6fa', - lawngreen: '#7cfc00', - lemonchiffon: '#fffacd', - lightblue: '#add8e6', - lightcoral: '#f08080', - lightcyan: '#e0ffff', - lightgoldenrodyellow: '#fafad2', - lightgray: '#d3d3d3', - lightgreen: '#90ee90', - lightgrey: '#d3d3d3', - lightpink: '#ffb6c1', - lightsalmon: '#ffa07a', - lightseagreen: '#20b2aa', - lightskyblue: '#87cefa', - lightslategray: '#778899', - lightslategrey: '#778899', - lightsteelblue: '#b0c4de', - lightyellow: '#ffffe0', - lime: '#00ff00', - limegreen: '#32cd32', - linen: '#faf0e6', - magenta: '#ff00ff', - maroon: '#800000', - mediumaquamarine: '#66cdaa', - mediumblue: '#0000cd', - mediumorchid: '#ba55d3', - mediumpurple: '#9370db', - mediumseagreen: '#3cb371', - mediumslateblue: '#7b68ee', - mediumspringgreen: '#00fa9a', - mediumturquoise: '#48d1cc', - mediumvioletred: '#c71585', - midnightblue: '#191970', - mintcream: '#f5fffa', - mistyrose: '#ffe4e1', - moccasin: '#ffe4b5', - navajowhite: '#ffdead', - navy: '#000080', - oldlace: '#fdf5e6', - olive: '#808000', - olivedrab: '#6b8e23', - orange: '#ffa500', - orangered: '#ff4500', - orchid: '#da70d6', - palegoldenrod: '#eee8aa', - palegreen: '#98fb98', - paleturquoise: '#afeeee', - palevioletred: '#db7093', - papayawhip: '#ffefd5', - peachpuff: '#ffdab9', - peru: '#cd853f', - pink: '#ffc0cb', - plum: '#dda0dd', - powderblue: '#b0e0e6', - purple: '#800080', - rebeccapurple: '#663399', - red: '#ff0000', - rosybrown: '#bc8f8f', - royalblue: '#4169e1', - saddlebrown: '#8b4513', - salmon: '#fa8072', - sandybrown: '#f4a460', - seagreen: '#2e8b57', - seashell: '#fff5ee', - sienna: '#a0522d', - silver: '#c0c0c0', - skyblue: '#87ceeb', - slateblue: '#6a5acd', - slategray: '#708090', - slategrey: '#708090', - snow: '#fffafa', - springgreen: '#00ff7f', - steelblue: '#4682b4', - tan: '#d2b48c', - teal: '#008080', - thistle: '#d8bfd8', - tomato: '#ff6347', - turquoise: '#40e0d0', - violet: '#ee82ee', - wheat: '#f5deb3', - white: '#ffffff', - whitesmoke: '#f5f5f5', - yellow: '#ffff00', - yellowgreen: '#9acd3', -} as const; diff --git a/packages/types/src/definitions/Colour.type.ts b/packages/types/src/definitions/Colour.type.ts new file mode 100644 index 000000000..2a17b08f9 --- /dev/null +++ b/packages/types/src/definitions/Colour.type.ts @@ -0,0 +1 @@ +export type RGBColour = { [key in 'red' | 'green' | 'blue' | 'alpha']: number }; diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 0629ffc81..2d22cee08 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -122,3 +122,6 @@ export { isTimerLifeCycle, } from './utils/guards.js'; export type { MaybeNumber, MaybeString } from './utils/utils.type.js'; + +// Colour +export type { RGBColour } from './definitions/Colour.type.js'; diff --git a/packages/utils/index.ts b/packages/utils/index.ts index 8e2933083..ef111f0c7 100644 --- a/packages/utils/index.ts +++ b/packages/utils/index.ts @@ -90,3 +90,13 @@ export { } from './src/feature/spreadsheet-import/spreadsheetImport.js'; export { isPlaybackActive } from './src/playback-utils/playbackstate.js'; + +//Colour +export { + colourToHex, + cssOrHexToColour, + hexToColour, + isLightColour, + mixColours, + CssColours, +} from './src/colour/colour.utils.js'; diff --git a/packages/utils/src/colour/colour.utils.ts b/packages/utils/src/colour/colour.utils.ts new file mode 100644 index 000000000..951763dc3 --- /dev/null +++ b/packages/utils/src/colour/colour.utils.ts @@ -0,0 +1,237 @@ +import type { RGBColour } from 'ontime-types'; + +import { isColourHex } from '../regex-utils/isColourHex.js'; + +// naive colour mix +export function mixColours(colour1: RGBColour, colour2: RGBColour, p: number = 0.5) { + const w1 = p; + const w2 = 1 - w1; + + return { + red: Math.round(colour1.red * w1 + colour2.red * w2), + green: Math.round(colour1.green * w1 + colour2.green * w2), + blue: Math.round(colour1.blue * w1 + colour2.blue * w2), + alpha: 1, + }; +} + +export function colourToHex(colour: RGBColour): string { + const alpha = Math.round(colour.alpha * 255) + .toString(16) + .padStart(2, '0'); + const red = colour.red.toString(16).padStart(2, '0'); + const green = colour.green.toString(16).padStart(2, '0'); + const blue = colour.blue.toString(16).padStart(2, '0'); + return '#' + red + green + blue + alpha; +} + +export function cssOrHexToColour(colour: string): RGBColour | null { + if (colour.startsWith('#')) return hexToColour(colour); + const maybeCssColour = colour.toLocaleLowerCase(); + if (maybeCssColour in CssColours) { + return hexToColour(CssColours[maybeCssColour]); + } + return null; +} + +export function hexToColour(hexColour: string): RGBColour | null { + if (!isColourHex(hexColour)) return null; + let hex = hexColour.toLocaleLowerCase(); + hex = hex.replace(/^#/, ''); + + let alpha = 1; + + // full length hex #FFFFFFFF + if (hex.length === 8) { + const alphaPart = hex.slice(6, 8); + alpha = parseInt(alphaPart, 16) / 255; + hex = hex.slice(0, 6); + } + + // compressed hex with alpha #FFFF + if (hex.length === 4) { + const alphaPart = hex.slice(3, 4).repeat(2); + alpha = parseInt(alphaPart, 16) / 255; + hex = hex.slice(0, 3); + } + + // compressed hex without alpha or after the alpha channel has been removed + // here all the values duplicated to create a 6 length hex value + if (hex.length === 3) { + hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; + } + + const number = parseInt(hex, 16); + const red = number >> 16; + const green = (number >> 8) & 255; + const blue = number & 255; + + if (isNaN(red) || isNaN(green) || isNaN(blue) || isNaN(alpha)) return null; + + return { red, green, blue, alpha }; +} + +/** + * Calculates if black or white is the best contras + * + * @returns true if the colour is light -> the best contrast is black + * + * is done with YIQ calculation + * @link https://24ways.org/2010/calculating-color-contrast + */ +export function isLightColour(colour: RGBColour): boolean { + const yiq = (colour.red * 299 + colour.green * 587 + colour.blue * 114) / 1000; + return yiq >= 128; +} + +//https://developer.mozilla.org/en-US/docs/Web/CSS/named-color +export const CssColours: Record = { + aliceblue: '#f0f8ff', + antiquewhite: '#faebd7', + aqua: '#00ffff', + aquamarine: '#7fffd4', + azure: '#f0ffff', + beige: '#f5f5dc', + bisque: '#ffe4c4', + black: '#000000', + blanchedalmond: '#ffebcd', + blue: '#0000ff', + blueviolet: '#8a2be2', + brown: '#a52a2a', + burlywood: '#deb887', + cadetblue: '#5f9ea0', + chartreuse: '#7fff00', + chocolate: '#d2691e', + coral: '#ff7f50', + cornflowerblue: '#6495ed', + cornsilk: '#fff8dc', + crimson: '#dc143c', + cyan: '#00ffff', + darkblue: '#00008b', + darkcyan: '#008b8b', + darkgoldenrod: '#b8860b', + darkgray: '#a9a9a9', + darkgreen: '#006400', + darkgrey: '#a9a9a9', + darkkhaki: '#bdb76b', + darkmagenta: '#8b008b', + darkolivegreen: '#556b2f', + darkorange: '#ff8c00', + darkorchid: '#9932cc', + darkred: '#8b0000', + darksalmon: '#e9967a', + darkseagreen: '#8fbc8f', + darkslateblue: '#483d8b', + darkslategray: '#2f4f4f', + darkslategrey: '#2f4f4f', + darkturquoise: '#00ced1', + darkviolet: '#9400d3', + deeppink: '#ff1493', + deepskyblue: '#00bfff', + dimgray: '#696969', + dimgrey: '#696969', + dodgerblue: '#1e90ff', + firebrick: '#b22222', + floralwhite: '#fffaf0', + forestgreen: '#228b22', + fuchsia: '#ff00ff', + gainsboro: '#dcdcdc', + ghostwhite: '#f8f8ff', + goldenrod: '#daa520', + gold: '#ffd700', + gray: '#808080', + green: '#008000', + greenyellow: '#adff2f', + grey: '#808080', + honeydew: '#f0fff0', + hotpink: '#ff69b4', + indianred: '#cd5c5c', + indigo: '#4b0082', + ivory: '#fffff0', + khaki: '#f0e68c', + lavenderblush: '#fff0f5', + lavender: '#e6e6fa', + lawngreen: '#7cfc00', + lemonchiffon: '#fffacd', + lightblue: '#add8e6', + lightcoral: '#f08080', + lightcyan: '#e0ffff', + lightgoldenrodyellow: '#fafad2', + lightgray: '#d3d3d3', + lightgreen: '#90ee90', + lightgrey: '#d3d3d3', + lightpink: '#ffb6c1', + lightsalmon: '#ffa07a', + lightseagreen: '#20b2aa', + lightskyblue: '#87cefa', + lightslategray: '#778899', + lightslategrey: '#778899', + lightsteelblue: '#b0c4de', + lightyellow: '#ffffe0', + lime: '#00ff00', + limegreen: '#32cd32', + linen: '#faf0e6', + magenta: '#ff00ff', + maroon: '#800000', + mediumaquamarine: '#66cdaa', + mediumblue: '#0000cd', + mediumorchid: '#ba55d3', + mediumpurple: '#9370db', + mediumseagreen: '#3cb371', + mediumslateblue: '#7b68ee', + mediumspringgreen: '#00fa9a', + mediumturquoise: '#48d1cc', + mediumvioletred: '#c71585', + midnightblue: '#191970', + mintcream: '#f5fffa', + mistyrose: '#ffe4e1', + moccasin: '#ffe4b5', + navajowhite: '#ffdead', + navy: '#000080', + oldlace: '#fdf5e6', + olive: '#808000', + olivedrab: '#6b8e23', + orange: '#ffa500', + orangered: '#ff4500', + orchid: '#da70d6', + palegoldenrod: '#eee8aa', + palegreen: '#98fb98', + paleturquoise: '#afeeee', + palevioletred: '#db7093', + papayawhip: '#ffefd5', + peachpuff: '#ffdab9', + peru: '#cd853f', + pink: '#ffc0cb', + plum: '#dda0dd', + powderblue: '#b0e0e6', + purple: '#800080', + rebeccapurple: '#663399', + red: '#ff0000', + rosybrown: '#bc8f8f', + royalblue: '#4169e1', + saddlebrown: '#8b4513', + salmon: '#fa8072', + sandybrown: '#f4a460', + seagreen: '#2e8b57', + seashell: '#fff5ee', + sienna: '#a0522d', + silver: '#c0c0c0', + skyblue: '#87ceeb', + slateblue: '#6a5acd', + slategray: '#708090', + slategrey: '#708090', + snow: '#fffafa', + springgreen: '#00ff7f', + steelblue: '#4682b4', + tan: '#d2b48c', + teal: '#008080', + thistle: '#d8bfd8', + tomato: '#ff6347', + turquoise: '#40e0d0', + violet: '#ee82ee', + wheat: '#f5deb3', + white: '#ffffff', + whitesmoke: '#f5f5f5', + yellow: '#ffff00', + yellowgreen: '#9acd3', +} as const; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2a217c56e..f8240474c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -137,9 +137,6 @@ importers: axios: specifier: ^1.9.0 version: 1.9.0 - color: - specifier: ^4.2.3 - version: 4.2.3 csv-stringify: specifier: ^6.4.5 version: 6.4.5 @@ -189,9 +186,6 @@ importers: '@tanstack/eslint-plugin-query': specifier: ^5.8.4 version: 5.8.4(eslint@8.56.0)(typescript@5.5.3) - '@types/color': - specifier: ^3.0.3 - version: 3.0.3 '@types/prismjs': specifier: ^1.26.5 version: 1.26.5 @@ -2234,15 +2228,6 @@ packages: '@types/chai@5.2.2': resolution: {integrity: sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==} - '@types/color-convert@2.0.0': - resolution: {integrity: sha512-m7GG7IKKGuJUXvkZ1qqG3ChccdIM/qBBo913z+Xft0nKCX4hAU/IxKwZBU4cpRZ7GS5kV4vOblUkILtSShCPXQ==} - - '@types/color-name@1.1.1': - resolution: {integrity: sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==} - - '@types/color@3.0.3': - resolution: {integrity: sha512-X//qzJ3d3Zj82J9sC/C18ZY5f43utPbAJ6PhYt/M7uG6etcF6MRpKdN880KBy43B0BMzSfeT96MzrsNjFI3GbA==} - '@types/connect@3.4.35': resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==} @@ -2887,16 +2872,9 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - color-string@1.9.1: - resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} - color2k@2.0.2: resolution: {integrity: sha512-kJhwH5nAwb34tmyuqq/lgjEKzlFXn1U99NlnB6Ws4qVaERcRUYeYP1cBw6BJ4vxaWStAUEef4WMr7WjOCnBt8w==} - color@4.2.3: - resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} - engines: {node: '>=12.5.0'} - combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -3898,9 +3876,6 @@ packages: is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - is-arrayish@0.3.2: - resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} - is-bigint@1.0.4: resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} @@ -5003,9 +4978,6 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - simple-swizzle@0.2.2: - resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} - simple-update-notifier@2.0.0: resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} engines: {node: '>=10'} @@ -7646,16 +7618,6 @@ snapshots: dependencies: '@types/deep-eql': 4.0.2 - '@types/color-convert@2.0.0': - dependencies: - '@types/color-name': 1.1.1 - - '@types/color-name@1.1.1': {} - - '@types/color@3.0.3': - dependencies: - '@types/color-convert': 2.0.0 - '@types/connect@3.4.35': dependencies: '@types/node': 22.15.26 @@ -8526,18 +8488,8 @@ snapshots: color-name@1.1.4: {} - color-string@1.9.1: - dependencies: - color-name: 1.1.4 - simple-swizzle: 0.2.2 - color2k@2.0.2: {} - color@4.2.3: - dependencies: - color-convert: 2.0.1 - color-string: 1.9.1 - combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 @@ -9819,8 +9771,6 @@ snapshots: is-arrayish@0.2.1: {} - is-arrayish@0.3.2: {} - is-bigint@1.0.4: dependencies: has-bigints: 1.0.2 @@ -10935,10 +10885,6 @@ snapshots: signal-exit@4.1.0: {} - simple-swizzle@0.2.2: - dependencies: - is-arrayish: 0.3.2 - simple-update-notifier@2.0.0: dependencies: semver: 7.6.2