Add composite layer preview, configurable LED count, and notification fire button to CSS test modal

- Composite sources show per-layer strip canvases with composite result on top
- Server sends composite wire format with per-layer RGB data
- LED count is configurable via input field, persisted in localStorage
- Notification sources show a bell fire button on the strip preview
- Composite with notification layers shows per-layer fire buttons
- Fixed stale WS frame bug with generation counter and unique consumer IDs
- Modal width is now fixed at 700px to prevent layout jumps
- Target card composite layers now use same-height canvases

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-12 20:17:54 +03:00
parent f2162133a8
commit 97db63824e
9 changed files with 359 additions and 33 deletions

View File

@@ -119,6 +119,10 @@
}
/* Color strip test preview */
.css-test-strip-wrap {
position: relative;
}
.css-test-strip-canvas {
display: block;
width: 100%;
@@ -128,6 +132,30 @@
image-rendering: pixelated;
}
.css-test-fire-btn {
position: absolute;
right: 6px;
top: 50%;
transform: translateY(-50%);
width: 32px;
height: 32px;
border: none;
border-radius: 6px;
background: rgba(255, 255, 255, 0.1);
color: #fff;
font-size: 16px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background 0.15s;
line-height: 1;
}
.css-test-fire-btn:hover {
background: rgba(255, 255, 255, 0.25);
}
.css-test-rect {
display: grid;
grid-template-columns: 14px 1fr 14px;
@@ -178,7 +206,71 @@
font-size: 0.9em;
}
#test-css-source-modal.css-test-wide .modal-content {
/* Composite layers preview */
.css-test-layers {
display: flex;
flex-direction: column;
gap: 4px;
}
.css-test-layer {
position: relative;
}
.css-test-layer-canvas {
display: block;
width: 100%;
height: 48px;
border-radius: 4px;
image-rendering: pixelated;
background: #111;
}
.css-test-layer-label {
position: absolute;
left: 4px;
top: 50%;
transform: translateY(-50%);
font-size: 0.6rem;
font-family: var(--font-mono, monospace);
color: #fff;
text-shadow: 0 0 3px rgba(0,0,0,0.9), 0 0 6px rgba(0,0,0,0.6);
pointer-events: none;
opacity: 0;
transition: opacity 0.15s;
white-space: nowrap;
}
.css-test-layers:hover .css-test-layer-label {
opacity: 1;
}
/* LED count control */
.css-test-led-control {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 0 0;
font-size: 0.85em;
}
.css-test-led-input {
width: 70px;
padding: 3px 6px;
border: 1px solid var(--border-color, #333);
border-radius: 4px;
background: var(--input-bg, #1a1a2e);
color: var(--text-color, #e0e0e0);
font-size: 0.85em;
text-align: center;
}
.css-test-led-apply {
padding: 3px 10px;
font-size: 0.8em;
}
#test-css-source-modal .modal-content {
max-width: 700px;
}