From 8de51da5a5c8dd0c416a3834ce36f81ca4034fbc Mon Sep 17 00:00:00 2001 From: David Montero Crespo Date: Mon, 11 May 2026 12:14:36 -0300 Subject: [PATCH] feat(simulator): wire color palette from PR #170 + Copilot suggestions - Add color picker button to SelectionActionBar for wire selections - Toggle palette using WIRE_KEY_COLORS swatches - Pass currentColor and onColorChange from SimulatorCanvas - Reset showPalette on kind/onColorChange change (Copilot suggestion) - Use t('editor.selectionBar.changeColor') for title/aria-label (Copilot suggestion) - Add changeColor i18n key to all 9 locale files Co-authored-by: naweiss --- .../simulator/SelectionActionBar.tsx | 103 ++++++++++++++++++ .../components/simulator/SimulatorCanvas.tsx | 6 + frontend/src/i18n/locales/de/common2.json | 1 + frontend/src/i18n/locales/en/common2.json | 1 + frontend/src/i18n/locales/es/common2.json | 1 + frontend/src/i18n/locales/fr/common2.json | 1 + frontend/src/i18n/locales/it/common2.json | 1 + frontend/src/i18n/locales/ja/common2.json | 1 + frontend/src/i18n/locales/pt-br/common2.json | 1 + frontend/src/i18n/locales/ru/common2.json | 1 + frontend/src/i18n/locales/zh-cn/common2.json | 1 + 11 files changed, 118 insertions(+) diff --git a/frontend/src/components/simulator/SelectionActionBar.tsx b/frontend/src/components/simulator/SelectionActionBar.tsx index 52c33b49..6d186e9a 100644 --- a/frontend/src/components/simulator/SelectionActionBar.tsx +++ b/frontend/src/components/simulator/SelectionActionBar.tsx @@ -18,6 +18,7 @@ import React, { useEffect, useRef } from 'react'; import { useTranslation } from 'react-i18next'; +import { WIRE_KEY_COLORS } from '../../utils/wireUtils'; export type SelectionKind = 'wire' | 'component' | 'board'; @@ -30,6 +31,8 @@ interface SelectionActionBarProps { onDelete: () => void; onRotate?: () => void; onDeselect: () => void; + onColorChange?: (color: string) => void; + currentColor?: string; } const ICON_SIZE = 16; @@ -126,12 +129,22 @@ export const SelectionActionBar: React.FC = ({ onDelete, onRotate, onDeselect, + onColorChange, + currentColor, }) => { const { t } = useTranslation(); + const [showPalette, setShowPalette] = React.useState(false); const containerRef = useRef(null); const deleteRef = useRef(null); const rotateRef = useRef(null); const deselectRef = useRef(null); + const colorToggleRef = useRef(null); + + // Reset the palette when the selection kind or colour-change handler changes + // (i.e. the user switched from one wire to another, or deselected). + useEffect(() => { + setShowPalette(false); + }, [kind, onColorChange]); // Stop native touch events from reaching the canvas listener so it can't // call preventDefault on touchend (which would kill the synthetic click). @@ -154,6 +167,7 @@ export const SelectionActionBar: React.FC = ({ useTouchSafeAction(deleteRef, onDelete); useTouchSafeAction(rotateRef, onRotate ?? noop); useTouchSafeAction(deselectRef, onDeselect); + useTouchSafeAction(colorToggleRef, () => setShowPalette(!showPalette)); if (!kind) return null; @@ -163,6 +177,8 @@ export const SelectionActionBar: React.FC = ({ role="toolbar" aria-label={t('editor.selectionBar.label')} className="selection-action-bar" + onMouseDown={(e) => e.stopPropagation()} + onClick={(e) => e.stopPropagation()} style={{ position: 'absolute', top: 12, @@ -196,6 +212,64 @@ export const SelectionActionBar: React.FC = ({ {label} + {kind === 'wire' && onColorChange && ( +
+ + + {showPalette && ( +
+ {Object.values(WIRE_KEY_COLORS).map((color) => ( + { + onColorChange(color); + setShowPalette(false); + }} + /> + ))} +
+ )} +
+ )} + {canRotate && onRotate && (