Add rotating gradient border on running LED target cards
Animated conic gradient spins around the card edge using CSS Houdini @property for smooth angle interpolation. Skips the left edge when a custom card color stripe is assigned (data-has-color attribute). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -99,6 +99,68 @@ section {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Running target: rotating gradient border ── */
|
||||||
|
@property --border-angle {
|
||||||
|
syntax: '<angle>';
|
||||||
|
initial-value: 0deg;
|
||||||
|
inherits: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-running {
|
||||||
|
border-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* When card has a custom color stripe, keep it and shift the animated border away from the left edge */
|
||||||
|
.card-running[data-has-color]::before {
|
||||||
|
inset: 0 0 0 3px;
|
||||||
|
border-left: none;
|
||||||
|
border-radius: 0 8px 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-running::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
border-radius: inherit;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
background:
|
||||||
|
conic-gradient(
|
||||||
|
from var(--border-angle),
|
||||||
|
var(--primary-color),
|
||||||
|
rgba(255,255,255,0.1) 25%,
|
||||||
|
var(--primary-color) 50%,
|
||||||
|
rgba(255,255,255,0.1) 75%,
|
||||||
|
var(--primary-color)
|
||||||
|
) border-box;
|
||||||
|
-webkit-mask:
|
||||||
|
linear-gradient(#fff 0 0) padding-box,
|
||||||
|
linear-gradient(#fff 0 0);
|
||||||
|
-webkit-mask-composite: xor;
|
||||||
|
mask:
|
||||||
|
linear-gradient(#fff 0 0) padding-box,
|
||||||
|
linear-gradient(#fff 0 0);
|
||||||
|
mask-composite: exclude;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 2;
|
||||||
|
animation: rotateBorder 4s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rotateBorder {
|
||||||
|
to { --border-angle: 360deg; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="light"] .card-running::before {
|
||||||
|
background:
|
||||||
|
conic-gradient(
|
||||||
|
from var(--border-angle),
|
||||||
|
var(--primary-color),
|
||||||
|
rgba(0,0,0,0.05) 25%,
|
||||||
|
var(--primary-color) 50%,
|
||||||
|
rgba(0,0,0,0.05) 75%,
|
||||||
|
var(--primary-color)
|
||||||
|
) border-box;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Card entrance animation ── */
|
/* ── Card entrance animation ── */
|
||||||
@keyframes cardEnter {
|
@keyframes cardEnter {
|
||||||
from { opacity: 0; transform: translateY(12px); }
|
from { opacity: 0; transform: translateY(12px); }
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ export function wrapCard({
|
|||||||
const actionsClass = type === 'template-card' ? 'template-card-actions' : 'card-actions';
|
const actionsClass = type === 'template-card' ? 'template-card-actions' : 'card-actions';
|
||||||
const colorStyle = cardColorStyle(id);
|
const colorStyle = cardColorStyle(id);
|
||||||
return `
|
return `
|
||||||
<div class="${type}${classes ? ' ' + classes : ''}" ${dataAttr}="${id}"${colorStyle ? ` style="${colorStyle}"` : ''}>
|
<div class="${type}${classes ? ' ' + classes : ''}" ${dataAttr}="${id}"${colorStyle ? ` style="${colorStyle}" data-has-color="1"` : ''}>
|
||||||
<div class="card-top-actions">
|
<div class="card-top-actions">
|
||||||
${topButtons}
|
${topButtons}
|
||||||
<button class="card-remove-btn" onclick="${removeOnclick}" title="${removeTitle}">✕</button>
|
<button class="card-remove-btn" onclick="${removeOnclick}" title="${removeTitle}">✕</button>
|
||||||
|
|||||||
@@ -978,6 +978,7 @@ export function createTargetCard(target, deviceMap, colorStripSourceMap, valueSo
|
|||||||
return wrapCard({
|
return wrapCard({
|
||||||
dataAttr: 'data-target-id',
|
dataAttr: 'data-target-id',
|
||||||
id: target.id,
|
id: target.id,
|
||||||
|
classes: isProcessing ? 'card-running' : '',
|
||||||
removeOnclick: `deleteTarget('${target.id}')`,
|
removeOnclick: `deleteTarget('${target.id}')`,
|
||||||
removeTitle: t('common.delete'),
|
removeTitle: t('common.delete'),
|
||||||
content: `
|
content: `
|
||||||
|
|||||||
Reference in New Issue
Block a user