CSS: add GradientColorStripSource with visual editor

- Backend: GradientColorStripSource storage model, GradientColorStripStream
  with numpy interpolation (bidirectional stops, auto-size from device LED count),
  ColorStop Pydantic schema, API create/update/guard routes
- Frontend: gradient editor modal (canvas preview, draggable markers, stop rows),
  CSS hard-edge card swatch, locale keys (en + ru)
- Fixes: stop row mousedown no longer rebuilds DOM (buttons now clickable),
  position input max-width, bidir/remove button static width

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-20 19:35:41 +03:00
parent 2a8e2daefc
commit 7479b1fb8d
12 changed files with 731 additions and 29 deletions

View File

@@ -571,9 +571,19 @@
"color_strip.delete.referenced": "Cannot delete: this source is in use by a target",
"color_strip.error.name_required": "Please enter a name",
"color_strip.type": "Type:",
"color_strip.type.hint": "Picture Source derives LED colors from a screen capture. Static Color fills all LEDs with a single constant color.",
"color_strip.type.hint": "Picture Source derives LED colors from a screen capture. Static Color fills all LEDs with a single constant color. Gradient distributes a color gradient across all LEDs.",
"color_strip.type.picture": "Picture Source",
"color_strip.type.static": "Static Color",
"color_strip.type.gradient": "Gradient",
"color_strip.static_color": "Color:",
"color_strip.static_color.hint": "The solid color that will be sent to all LEDs on the strip."
"color_strip.static_color.hint": "The solid color that will be sent to all LEDs on the strip.",
"color_strip.gradient.preview": "Gradient:",
"color_strip.gradient.preview.hint": "Visual preview. Click the marker track below to add a stop. Drag markers to reposition.",
"color_strip.gradient.stops": "Color Stops:",
"color_strip.gradient.stops.hint": "Each stop defines a color at a relative position (0.0 = start, 1.0 = end). The ↔ button adds a right-side color to create a hard edge at that stop.",
"color_strip.gradient.stops_count": "stops",
"color_strip.gradient.add_stop": "+ Add Stop",
"color_strip.gradient.position": "Position (0.01.0)",
"color_strip.gradient.bidir.hint": "Add a second color on the right side of this stop to create a hard edge in the gradient.",
"color_strip.gradient.min_stops": "Gradient must have at least 2 stops"
}