mirror of
https://github.com/OFFIS-ESC/constellation-analyzer
synced 2026-01-27 07:43:41 +00:00
fix: improve minimized group label contrast and typography
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 <noreply@anthropic.com>
This commit is contained in:
parent
60748a2235
commit
f29c55a1b8
1 changed files with 27 additions and 2 deletions
|
|
@ -2,6 +2,21 @@ import { memo, useState, useMemo } from 'react';
|
||||||
import { NodeProps, NodeResizer, useStore, Handle, Position } from '@xyflow/react';
|
import { NodeProps, NodeResizer, useStore, Handle, Position } from '@xyflow/react';
|
||||||
import type { Group } from '../../types';
|
import type { Group } from '../../types';
|
||||||
import type { Actor } 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
|
* GroupNode - Simple label overlay for React Flow's native group nodes
|
||||||
|
|
@ -91,6 +106,10 @@ const GroupNode = ({ id, data, selected }: NodeProps<Group>) => {
|
||||||
? data.color.replace(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*[\d.]+)?\)/, 'rgb($1, $2, $3)')
|
? data.color.replace(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*[\d.]+)?\)/, 'rgb($1, $2, $3)')
|
||||||
: '#f0f2f5';
|
: '#f0f2f5';
|
||||||
|
|
||||||
|
// Calculate contrast color for text based on background
|
||||||
|
const hexColor = rgbToHex(solidColor);
|
||||||
|
const textColor = getContrastColor(hexColor);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="group-minimized"
|
className="group-minimized"
|
||||||
|
|
@ -175,10 +194,16 @@ const GroupNode = ({ id, data, selected }: NodeProps<Group>) => {
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="text-sm font-semibold text-gray-800 leading-tight">
|
<div
|
||||||
|
className="text-base font-bold leading-tight"
|
||||||
|
style={{ color: textColor }}
|
||||||
|
>
|
||||||
{data.label}
|
{data.label}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-gray-600 mt-1.5">
|
<div
|
||||||
|
className="text-xs font-medium leading-tight mt-1.5"
|
||||||
|
style={{ color: textColor, opacity: 0.7 }}
|
||||||
|
>
|
||||||
{data.actorIds.length} actor{data.actorIds.length !== 1 ? 's' : ''}
|
{data.actorIds.length} actor{data.actorIds.length !== 1 ? 's' : ''}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue