|
| 1 | +import { DiscourseNode } from "~/types"; |
| 2 | + |
| 3 | +// Color palette similar to Roam's implementation |
| 4 | +const COLOR_PALETTE: Record<string, string> = { |
| 5 | + black: "#1d1d1d", |
| 6 | + blue: "#4263eb", |
| 7 | + green: "#099268", |
| 8 | + grey: "#adb5bd", |
| 9 | + lightBlue: "#4dabf7", |
| 10 | + lightGreen: "#40c057", |
| 11 | + lightRed: "#ff8787", |
| 12 | + lightViolet: "#e599f7", |
| 13 | + orange: "#f76707", |
| 14 | + red: "#e03131", |
| 15 | + violet: "#ae3ec9", |
| 16 | + white: "#ffffff", |
| 17 | + yellow: "#ffc078", |
| 18 | +}; |
| 19 | + |
| 20 | +const COLOR_ARRAY = Object.keys(COLOR_PALETTE); |
| 21 | + |
| 22 | +// TODO switch to colord - https://linear.app/discourse-graphs/issue/ENG-836/button-like-css-styling-for-node-tag |
| 23 | +export const getContrastColor = (bgColor: string): string => { |
| 24 | + const hex = bgColor.replace("#", ""); |
| 25 | + |
| 26 | + if (hex.length !== 6) return "#000000"; |
| 27 | + |
| 28 | + const r = parseInt(hex.substring(0, 2), 16); |
| 29 | + const g = parseInt(hex.substring(2, 4), 16); |
| 30 | + const b = parseInt(hex.substring(4, 6), 16); |
| 31 | + |
| 32 | + if (isNaN(r) || isNaN(g) || isNaN(b)) return "#000000"; |
| 33 | + |
| 34 | + const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255; |
| 35 | + |
| 36 | + return luminance > 0.5 ? "#000000" : "#ffffff"; |
| 37 | +}; |
| 38 | + |
| 39 | +export const getNodeTagColors = ( |
| 40 | + nodeType: DiscourseNode, |
| 41 | + nodeIndex: number, |
| 42 | +): { backgroundColor: string; textColor: string } => { |
| 43 | + const customColor = nodeType.color || ""; |
| 44 | + |
| 45 | + const safeIndex = |
| 46 | + nodeIndex >= 0 && nodeIndex < COLOR_ARRAY.length ? nodeIndex : 0; |
| 47 | + const paletteColorKey = COLOR_ARRAY[safeIndex]; |
| 48 | + const paletteColor = paletteColorKey |
| 49 | + ? COLOR_PALETTE[paletteColorKey] |
| 50 | + : COLOR_PALETTE.blue; |
| 51 | + |
| 52 | + const backgroundColor = customColor || paletteColor || "#4263eb"; |
| 53 | + const textColor = getContrastColor(backgroundColor); |
| 54 | + |
| 55 | + return { backgroundColor, textColor }; |
| 56 | +}; |
| 57 | + |
| 58 | + |
| 59 | +export const getAllDiscourseNodeColors = ( |
| 60 | + nodeTypes: DiscourseNode[], |
| 61 | +): Array<{ |
| 62 | + nodeType: DiscourseNode; |
| 63 | + colors: { backgroundColor: string; textColor: string }; |
| 64 | +}> => { |
| 65 | + return nodeTypes.map((nodeType, index) => ({ |
| 66 | + nodeType, |
| 67 | + colors: getNodeTagColors(nodeType, index), |
| 68 | + })); |
| 69 | +}; |
0 commit comments