feat: add opacity slider to zone color pickers (fixes #72)
The native <input type="color"> only supports 6-digit hex, stripping alpha and forcing background/border/text colors to be fully opaque on edit. Each color field now shows an opacity slider (0–100%) below the swatch. Values are stored as 8-digit hex (#rrggbbaa). Existing zones with 6-digit colors are handled transparently (alpha defaults to 100%). - colorUtils.ts: hexToRgba / rgbaToHex8 helpers - GroupRectModal: opacity sliders for all three color fields - 26 new tests across colorUtils and GroupRectModal
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Split a 6- or 8-digit hex color into its RGB hex and alpha (0–100).
|
||||
* 6-digit input returns alpha 100.
|
||||
* Invalid input returns { hex6: '#000000', alpha: 100 }.
|
||||
*/
|
||||
export function hexToRgba(hex: string): { hex6: string; alpha: number } {
|
||||
const clean = hex.replace('#', '')
|
||||
if (clean.length === 8) {
|
||||
const alphaByte = parseInt(clean.slice(6, 8), 16)
|
||||
return {
|
||||
hex6: `#${clean.slice(0, 6)}`,
|
||||
alpha: Math.round((alphaByte / 255) * 100),
|
||||
}
|
||||
}
|
||||
if (clean.length === 6) {
|
||||
return { hex6: `#${clean}`, alpha: 100 }
|
||||
}
|
||||
return { hex6: '#000000', alpha: 100 }
|
||||
}
|
||||
|
||||
/**
|
||||
* Combine a 6-digit hex color and an alpha (0–100) into an 8-digit hex.
|
||||
*/
|
||||
export function rgbaToHex8(hex6: string, alpha: number): string {
|
||||
const clamped = Math.max(0, Math.min(100, alpha))
|
||||
const alphaByte = Math.round((clamped / 100) * 255)
|
||||
const alphaHex = alphaByte.toString(16).padStart(2, '0')
|
||||
return `${hex6}${alphaHex}`
|
||||
}
|
||||
Reference in New Issue
Block a user