diff --git a/svelte-app/src/lib/export.ts b/svelte-app/src/lib/export.ts index 55a0a32..27bfae8 100644 --- a/svelte-app/src/lib/export.ts +++ b/svelte-app/src/lib/export.ts @@ -136,11 +136,16 @@ const TAG_PATH_RULES: Array<{ pattern: RegExp; path: string }> = [ /** Build Ignition tag path from device label and MCM name. * Format: System/{MCM}/{Category}/{SubCategory}/{Label} * Mappings derived from Excel device manifest suffixes. */ +/** Strip _PB/_SPB/_STPB suffixes from button labels — PLC uses S1, JR1, SS1 not S1_PB */ +function stripButtonSuffix(label: string): string { + return label.replace(/_S?T?PB$/i, ''); +} + function getIgnitionTagPath(label: string, mcm: string): string | null { if (!label) return null; if (/^MCM\d*/i.test(label)) return null; for (const rule of TAG_PATH_RULES) { - if (rule.pattern.test(label)) return `System/${mcm}/${rule.path}/${label}`; + if (rule.pattern.test(label)) return `System/${mcm}/${rule.path}/${stripButtonSuffix(label)}`; } return null; } diff --git a/svelte-app/src/lib/ignition-view.ts b/svelte-app/src/lib/ignition-view.ts index d1ee605..8777e6f 100644 --- a/svelte-app/src/lib/ignition-view.ts +++ b/svelte-app/src/lib/ignition-view.ts @@ -311,15 +311,35 @@ function generateElementBindings(elements: SvgElement[]): Record { propConfig[`${prefix}.state`] = stateBinding(n); propConfig[`${prefix}.priority`] = priorityBinding(n); - // Sub-element fill bindings + // Sub-element fill bindings — varies by device type + const isButton = /_(?:JR|S|SS|EN)\d/i.test(elName); + const isDpm = /_DPM\d*/i.test(elName); + if (el.elements && el.elements.length > 0) { - for (let m = 0; m < el.elements.length; m++) { - const sub = el.elements[m]; - if (sub.type === 'text') { - propConfig[`${prefix}.elements[${m}].fill.paint`] = textFillBinding(n); - } else { - // rect, path, etc. — background fill - propConfig[`${prefix}.elements[${m}].fill.paint`] = fillPaintBinding(n); + if (isDpm) { + // DPM: only elements[1] gets color binding (the black triangle) + // elements[0] stays as-is, elements[2] is transparent + if (el.elements.length > 1) { + propConfig[`${prefix}.elements[1].fill.paint`] = fillPaintBinding(n); + } + } else if (isButton) { + // Buttons: NO fill binding on elements[0] (background rect keeps static color) + // Only text elements get contrast color binding + for (let m = 0; m < el.elements.length; m++) { + const sub = el.elements[m]; + if (sub.type === 'text') { + propConfig[`${prefix}.elements[${m}].fill.paint`] = textFillBinding(n); + } + } + } else { + // Default: background gets color, text gets contrast + for (let m = 0; m < el.elements.length; m++) { + const sub = el.elements[m]; + if (sub.type === 'text') { + propConfig[`${prefix}.elements[${m}].fill.paint`] = textFillBinding(n); + } else { + propConfig[`${prefix}.elements[${m}].fill.paint`] = fillPaintBinding(n); + } } } }