mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-21 21:22:11 -03:00
feat(onboarding): enhance target highlighting with mask and pulsing effect
This commit is contained in:
@@ -8,6 +8,9 @@
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
z-index: var(--z-overlay);
|
||||
display: none;
|
||||
/* Use mask to create cutout for highlighted element */
|
||||
mask-composite: subtract;
|
||||
-webkit-mask-composite: subtract;
|
||||
}
|
||||
|
||||
.onboarding-overlay.active {
|
||||
@@ -19,10 +22,26 @@
|
||||
background: transparent;
|
||||
border: 3px solid var(--lora-accent);
|
||||
border-radius: var(--border-radius-base);
|
||||
box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.8);
|
||||
z-index: calc(var(--z-overlay) + 1);
|
||||
pointer-events: none;
|
||||
transition: all 0.3s ease;
|
||||
/* Add glow effect */
|
||||
box-shadow:
|
||||
0 0 0 2px rgba(24, 144, 255, 0.3),
|
||||
0 0 20px rgba(24, 144, 255, 0.2),
|
||||
inset 0 0 0 1px rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
/* Target element highlighting */
|
||||
.onboarding-target-highlight {
|
||||
position: relative;
|
||||
z-index: calc(var(--z-overlay) + 2) !important;
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
|
||||
/* Ensure highlighted elements are interactive */
|
||||
.onboarding-target-highlight * {
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
|
||||
.onboarding-popup {
|
||||
@@ -33,7 +52,7 @@
|
||||
padding: var(--space-3);
|
||||
min-width: 320px;
|
||||
max-width: 400px;
|
||||
z-index: calc(var(--z-overlay) + 2);
|
||||
z-index: calc(var(--z-overlay) + 3);
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
@@ -201,10 +220,16 @@
|
||||
|
||||
@keyframes onboarding-pulse {
|
||||
0%, 100% {
|
||||
box-shadow: 0 0 0 0 var(--lora-accent);
|
||||
box-shadow:
|
||||
0 0 0 2px rgba(24, 144, 255, 0.4),
|
||||
0 0 20px rgba(24, 144, 255, 0.3),
|
||||
inset 0 0 0 1px rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 0 0 8px transparent;
|
||||
box-shadow:
|
||||
0 0 0 4px rgba(24, 144, 255, 0.6),
|
||||
0 0 30px rgba(24, 144, 255, 0.4),
|
||||
inset 0 0 0 1px rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ export class OnboardingManager {
|
||||
this.overlay = null;
|
||||
this.spotlight = null;
|
||||
this.popup = null;
|
||||
this.currentTarget = null; // Track current highlighted element
|
||||
|
||||
// Available languages with SVG flags (using flag-icons)
|
||||
this.languages = [
|
||||
@@ -252,16 +253,15 @@ export class OnboardingManager {
|
||||
return;
|
||||
}
|
||||
|
||||
// Position spotlight
|
||||
// Clear previous target highlighting
|
||||
this.clearTargetHighlight();
|
||||
|
||||
// Position spotlight and create mask
|
||||
if (target && step.target !== 'body') {
|
||||
const rect = target.getBoundingClientRect();
|
||||
this.spotlight.style.left = `${rect.left - 5}px`;
|
||||
this.spotlight.style.top = `${rect.top - 5}px`;
|
||||
this.spotlight.style.width = `${rect.width + 10}px`;
|
||||
this.spotlight.style.height = `${rect.height + 10}px`;
|
||||
this.spotlight.style.display = 'block';
|
||||
this.highlightTarget(target);
|
||||
} else {
|
||||
this.spotlight.style.display = 'none';
|
||||
this.clearOverlayMask();
|
||||
}
|
||||
|
||||
// Update popup content
|
||||
@@ -344,6 +344,92 @@ export class OnboardingManager {
|
||||
popup.style.transform = 'none';
|
||||
}
|
||||
|
||||
// Highlight target element with mask approach
|
||||
highlightTarget(target) {
|
||||
const rect = target.getBoundingClientRect();
|
||||
const padding = 4; // Padding around the target element
|
||||
const offset = 3; // Shift spotlight up and left by 3px
|
||||
|
||||
// Position spotlight
|
||||
this.spotlight.style.left = `${rect.left - padding - offset}px`;
|
||||
this.spotlight.style.top = `${rect.top - padding - offset}px`;
|
||||
this.spotlight.style.width = `${rect.width + padding * 2}px`;
|
||||
this.spotlight.style.height = `${rect.height + padding * 2}px`;
|
||||
this.spotlight.style.display = 'block';
|
||||
|
||||
// Create mask for overlay to cut out the highlighted area
|
||||
this.createOverlayMask(rect, padding, offset);
|
||||
|
||||
// Add highlight class to target and ensure it's interactive
|
||||
target.classList.add('onboarding-target-highlight');
|
||||
this.currentTarget = target;
|
||||
|
||||
// Add pulsing animation
|
||||
this.spotlight.classList.add('onboarding-highlight');
|
||||
}
|
||||
|
||||
// Create mask for overlay to cut out highlighted area
|
||||
createOverlayMask(rect, padding, offset = 0) {
|
||||
const x = rect.left - padding - offset;
|
||||
const y = rect.top - padding - offset;
|
||||
const width = rect.width + padding * 2;
|
||||
const height = rect.height + padding * 2;
|
||||
|
||||
// Create SVG mask
|
||||
const maskId = 'onboarding-mask';
|
||||
let maskSvg = document.getElementById(maskId);
|
||||
|
||||
if (!maskSvg) {
|
||||
maskSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
||||
maskSvg.id = maskId;
|
||||
maskSvg.style.position = 'absolute';
|
||||
maskSvg.style.top = '0';
|
||||
maskSvg.style.left = '0';
|
||||
maskSvg.style.width = '100%';
|
||||
maskSvg.style.height = '100%';
|
||||
maskSvg.style.pointerEvents = 'none';
|
||||
document.body.appendChild(maskSvg);
|
||||
}
|
||||
|
||||
// Clear existing mask content
|
||||
maskSvg.innerHTML = `
|
||||
<defs>
|
||||
<mask id="overlay-mask">
|
||||
<rect width="100%" height="100%" fill="white"/>
|
||||
<rect x="${x}" y="${y}" width="${width}" height="${height}"
|
||||
rx="8" ry="8" fill="black"/>
|
||||
</mask>
|
||||
</defs>
|
||||
`;
|
||||
|
||||
// Apply mask to overlay
|
||||
this.overlay.style.mask = 'url(#overlay-mask)';
|
||||
this.overlay.style.webkitMask = 'url(#overlay-mask)';
|
||||
}
|
||||
|
||||
// Clear overlay mask
|
||||
clearOverlayMask() {
|
||||
this.overlay.style.mask = 'none';
|
||||
this.overlay.style.webkitMask = 'none';
|
||||
|
||||
const maskSvg = document.getElementById('onboarding-mask');
|
||||
if (maskSvg) {
|
||||
maskSvg.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// Clear target highlighting
|
||||
clearTargetHighlight() {
|
||||
if (this.currentTarget) {
|
||||
this.currentTarget.classList.remove('onboarding-target-highlight');
|
||||
this.currentTarget = null;
|
||||
}
|
||||
|
||||
if (this.spotlight) {
|
||||
this.spotlight.classList.remove('onboarding-highlight');
|
||||
}
|
||||
}
|
||||
|
||||
// Navigate to next step
|
||||
nextStep() {
|
||||
this.showStep(this.currentStep + 1);
|
||||
@@ -370,6 +456,9 @@ export class OnboardingManager {
|
||||
|
||||
// Clean up overlay elements
|
||||
cleanup() {
|
||||
this.clearTargetHighlight();
|
||||
this.clearOverlayMask();
|
||||
|
||||
if (this.overlay) {
|
||||
document.body.removeChild(this.overlay);
|
||||
this.overlay = null;
|
||||
|
||||
Reference in New Issue
Block a user