From 126ff4fafcba055b8c21233bc751df996a534e54 Mon Sep 17 00:00:00 2001 From: David Montero Crespo Date: Mon, 27 Jul 2026 18:27:30 +0200 Subject: [PATCH] feat(camera): el boton de camara pide el click con borde de hormigas en marcha MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cuatro tiras de gradiente repetido, una por borde, deslizando un periodo de guion por ciclo — fondo y no border porque un borde CSS no puede animar su dash-offset. currentColor hereda el color de estado (gris en reposo, rojo en error). Se apaga en streaming/solicitando, y con prefers-reduced-motion. Ojo del gato encerrado: el estilo inline usaba el shorthand background, que pisa el background-image de la clase — pasa a backgroundColor. --- frontend/src/App.css | 23 +++++++++++++++++++ .../src/components/simulator/CameraToggle.tsx | 15 ++++++++++-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/frontend/src/App.css b/frontend/src/App.css index 47df9d9c..c5791c9b 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -448,3 +448,26 @@ body { 0%, 100% { opacity: 0.4; transform: scale(0.85); } 50% { opacity: 1.0; transform: scale(1.0); } } + +/* Marching-ants attention border (CameraToggle while it wants a click): + four thin repeating-gradient strips, one per edge, sliding one dash + period per cycle. Drawn as backgrounds rather than a border because a + CSS border cannot animate its dash offset. Uses currentColor so the + ants inherit the button's state colour (grey idle, red on error). */ +@keyframes velxio-marching-ants { + to { background-position: 12px 0, -12px 100%, 0 -12px, 100% 12px; } +} +.velxio-ants { + background-image: + repeating-linear-gradient(90deg, currentColor 0 6px, transparent 6px 12px), + repeating-linear-gradient(90deg, currentColor 0 6px, transparent 6px 12px), + repeating-linear-gradient(0deg, currentColor 0 6px, transparent 6px 12px), + repeating-linear-gradient(0deg, currentColor 0 6px, transparent 6px 12px); + background-repeat: repeat-x, repeat-x, repeat-y, repeat-y; + background-size: 12px 1px, 12px 1px, 1px 12px, 1px 12px; + background-position: 0 0, 0 100%, 0 0, 100% 0; + animation: velxio-marching-ants 0.7s linear infinite; +} +@media (prefers-reduced-motion: reduce) { + .velxio-ants { animation: none; } +} diff --git a/frontend/src/components/simulator/CameraToggle.tsx b/frontend/src/components/simulator/CameraToggle.tsx index fe2c95f6..d6e8ef93 100644 --- a/frontend/src/components/simulator/CameraToggle.tsx +++ b/frontend/src/components/simulator/CameraToggle.tsx @@ -103,9 +103,20 @@ export const CameraToggle: React.FC = ({ boardId }) => { onClick={handleClick} disabled={!boardId || status === 'requesting'} title={tooltip} + // Ants while the button wants a click (idle after a failed/stopped + // auto-start, denied, error). Solid border once streaming or asking. + className={ + boardId && status !== 'streaming' && status !== 'requesting' + ? 'velxio-ants' + : undefined + } style={{ - background: isOn ? 'rgba(63,185,80,0.15)' : 'transparent', - border: `1px solid ${isOn ? '#3fb950' : '#555'}`, + // backgroundColor, NOT the background shorthand: inline shorthand + // would wipe the class's background-image and kill the ants. + backgroundColor: isOn ? 'rgba(63,185,80,0.15)' : 'transparent', + border: `1px solid ${ + isOn ? '#3fb950' : status === 'requesting' ? '#555' : 'transparent' + }`, borderRadius: 4, padding: '4px 10px', display: 'flex',