From f29c55a1b87f33b6094a258facdebf86f2739ca9 Mon Sep 17 00:00:00 2001 From: Jan-Henrik Bruhn Date: Mon, 20 Oct 2025 15:12:42 +0200 Subject: [PATCH] fix: improve minimized group label contrast and typography MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Applied luminosity-based contrast color calculation to minimized group labels, matching the same accessibility approach used for actor nodes. Changes: - Added rgbToHex() helper to convert rgb/rgba colors to hex format - Import getContrastColor() from colorUtils - Calculate text color based on background luminosity - Apply calculated color to both label and subtitle Typography updates to match actor nodes: - Main label: text-base font-bold (was text-sm font-semibold) - Subtitle: text-xs font-medium with 0.7 opacity (was text-gray-600) - Both use dynamic textColor instead of fixed gray values Benefits: - ✅ Readable labels on both light and dark group backgrounds - ✅ Consistent typography between actor nodes and group nodes - ✅ Follows WCAG 2.0 luminance contrast standards - ✅ Professional appearance across all color choices The minimized group labels now automatically switch between white and black text based on the background color's luminosity, ensuring optimal readability in all cases. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/components/Nodes/GroupNode.tsx | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/components/Nodes/GroupNode.tsx b/src/components/Nodes/GroupNode.tsx index 3de7b08..f9917b4 100644 --- a/src/components/Nodes/GroupNode.tsx +++ b/src/components/Nodes/GroupNode.tsx @@ -2,6 +2,21 @@ import { memo, useState, useMemo } from 'react'; import { NodeProps, NodeResizer, useStore, Handle, Position } from '@xyflow/react'; import type { Group } from '../../types'; import type { Actor } from '../../types'; +import { getContrastColor } from '../../utils/colorUtils'; + +/** + * Helper function to convert rgb/rgba color string to hex + */ +const rgbToHex = (rgb: string): string => { + const match = rgb.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*[\d.]+)?\)/); + if (!match) return '#000000'; + + const r = parseInt(match[1]).toString(16).padStart(2, '0'); + const g = parseInt(match[2]).toString(16).padStart(2, '0'); + const b = parseInt(match[3]).toString(16).padStart(2, '0'); + + return `#${r}${g}${b}`; +}; /** * GroupNode - Simple label overlay for React Flow's native group nodes @@ -91,6 +106,10 @@ const GroupNode = ({ id, data, selected }: NodeProps) => { ? data.color.replace(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*[\d.]+)?\)/, 'rgb($1, $2, $3)') : '#f0f2f5'; + // Calculate contrast color for text based on background + const hexColor = rgbToHex(solidColor); + const textColor = getContrastColor(hexColor); + return (
) => { textAlign: 'center', }} > -
+
{data.label}
-
+
{data.actorIds.length} actor{data.actorIds.length !== 1 ? 's' : ''}