Skip to content

Commit c3fb2ec

Browse files
committed
fix: onboarding highlight properly reveals elements, card positioned near target
1 parent 5f04556 commit c3fb2ec

2 files changed

Lines changed: 143 additions & 33 deletions

File tree

public/css/style.css

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4438,42 +4438,79 @@ tbody tr:hover {
44384438
position: fixed;
44394439
inset: 0;
44404440
z-index: 9999;
4441-
display: flex;
4442-
align-items: center;
4443-
justify-content: center;
4441+
pointer-events: none;
44444442
}
44454443

44464444
.onboarding-backdrop {
44474445
position: absolute;
44484446
inset: 0;
44494447
background: rgba(0, 0, 0, 0.7);
4450-
transition: opacity 0.25s ease;
4448+
pointer-events: none;
44514449
}
44524450

44534451
.onboarding-card {
4454-
position: relative;
4455-
z-index: 10001;
4452+
pointer-events: auto;
44564453
background: var(--bg-card);
44574454
border: 1px solid var(--border);
44584455
border-radius: var(--radius-xl);
4459-
padding: 40px 36px;
4460-
max-width: 480px;
4456+
padding: 32px 28px;
4457+
max-width: 440px;
44614458
width: 90%;
44624459
box-shadow: 0 24px 80px rgba(0, 0, 0, 0.6);
44634460
text-align: center;
4461+
position: fixed;
4462+
z-index: 10001;
4463+
}
4464+
4465+
.onboarding-card.centered {
4466+
top: 50%;
4467+
left: 50%;
4468+
transform: translate(-50%, -50%);
4469+
}
4470+
4471+
.onboarding-card .card-arrow {
4472+
position: absolute;
4473+
width: 14px;
4474+
height: 14px;
4475+
background: var(--bg-card);
4476+
border-left: 1px solid var(--border);
4477+
border-top: 1px solid var(--border);
4478+
z-index: 1;
4479+
}
4480+
4481+
.onboarding-card .card-arrow.up {
4482+
top: -8px;
4483+
left: 50%;
4484+
margin-left: -7px;
4485+
transform: rotate(45deg);
4486+
border-left-color: var(--border);
4487+
border-top-color: var(--border);
4488+
border-right: none;
4489+
border-bottom: none;
4490+
}
4491+
4492+
.onboarding-card .card-arrow.down {
4493+
bottom: -8px;
4494+
left: 50%;
4495+
margin-left: -7px;
4496+
transform: rotate(225deg);
4497+
border-left-color: var(--border);
4498+
border-top-color: var(--border);
4499+
border-right: none;
4500+
border-bottom: none;
44644501
}
44654502

44664503
.onboarding-card h2 {
4467-
font-size: 1.4rem;
4504+
font-size: 1.3rem;
44684505
font-weight: 700;
4469-
margin-bottom: 12px;
4506+
margin-bottom: 10px;
44704507
}
44714508

44724509
.onboarding-card p {
4473-
font-size: 0.92rem;
4510+
font-size: 0.9rem;
44744511
color: var(--text-secondary);
4475-
line-height: 1.65;
4476-
margin-bottom: 28px;
4512+
line-height: 1.6;
4513+
margin-bottom: 24px;
44774514
}
44784515

44794516
.onboarding-card .onboarding-actions {
@@ -4483,7 +4520,7 @@ tbody tr:hover {
44834520
}
44844521

44854522
.onboarding-card .onboarding-actions .btn {
4486-
min-width: 110px;
4523+
min-width: 100px;
44874524
}
44884525

44894526
.onboarding-highlight {
@@ -4497,7 +4534,7 @@ tbody tr:hover {
44974534
display: flex;
44984535
gap: 6px;
44994536
justify-content: center;
4500-
margin-bottom: 20px;
4537+
margin-bottom: 16px;
45014538
}
45024539

45034540
.onboarding-dot {

public/js/app.js

Lines changed: 91 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4063,22 +4063,84 @@ function applyOnboardingHighlight(selector) {
40634063
}
40644064
}
40654065

4066+
function positionOnboardingCard(selector) {
4067+
const card = $('#onboarding-card');
4068+
if (!card) return;
4069+
4070+
if (!selector) {
4071+
card.classList.add('centered');
4072+
const arrow = card.querySelector('.card-arrow');
4073+
if (arrow) arrow.remove();
4074+
return;
4075+
}
4076+
4077+
card.classList.remove('centered');
4078+
4079+
const el = document.querySelector(selector);
4080+
if (!el) return;
4081+
4082+
const elRect = el.getBoundingClientRect();
4083+
const cardW = 440;
4084+
const cardMaxH = window.innerHeight - 80;
4085+
const gap = 14;
4086+
4087+
// Remove old arrow and create a new one
4088+
const oldArrow = card.querySelector('.card-arrow');
4089+
if (oldArrow) oldArrow.remove();
4090+
const arrow = document.createElement('div');
4091+
arrow.className = 'card-arrow';
4092+
card.appendChild(arrow);
4093+
4094+
let top, arrowDir;
4095+
4096+
// Try below first
4097+
const spaceBelow = window.innerHeight - elRect.bottom;
4098+
const spaceAbove = elRect.top;
4099+
const approxCardH = Math.min(360, cardMaxH);
4100+
4101+
if (spaceBelow >= approxCardH + gap + 20) {
4102+
top = elRect.bottom + gap;
4103+
arrowDir = 'up';
4104+
} else if (spaceAbove >= approxCardH + gap + 20) {
4105+
top = elRect.top - gap - approxCardH;
4106+
arrowDir = 'down';
4107+
} else {
4108+
// Center as fallback
4109+
top = Math.max(20, (window.innerHeight - approxCardH) / 2);
4110+
arrowDir = null;
4111+
}
4112+
4113+
// Center card horizontally under the element, but clamp to viewport
4114+
let left = elRect.left + elRect.width / 2 - cardW / 2;
4115+
left = Math.max(16, Math.min(left, window.innerWidth - cardW - 16));
4116+
4117+
top = Math.max(16, Math.min(top, window.innerHeight - approxCardH - 16));
4118+
4119+
card.style.top = top + 'px';
4120+
card.style.left = left + 'px';
4121+
card.style.transform = 'none';
4122+
4123+
if (arrowDir) {
4124+
arrow.className = `card-arrow ${arrowDir}`;
4125+
} else {
4126+
arrow.remove();
4127+
}
4128+
}
4129+
40664130
function renderOnboardingStep(stepIndex) {
40674131
const card = $('#onboarding-card');
40684132
if (!card) return;
40694133

40704134
const step = ONBOARDING_STEPS[stepIndex];
4071-
const isLast = stepIndex === ONBOARDING_STEPS.length - 1;
4072-
const isFirst = stepIndex === 0;
40734135

40744136
let dotsHtml = '<div class="onboarding-dots">';
40754137
ONBOARDING_STEPS.forEach((_, i) => {
40764138
dotsHtml += `<span class="onboarding-dot ${i === stepIndex ? 'active' : ''}"></span>`;
40774139
});
40784140
dotsHtml += '</div>';
40794141

4080-
const leftBtn = step.buttons[0]; // Skip
4081-
const rightBtn = step.buttons[1]; // Start / Next / Got it!
4142+
const leftBtn = step.buttons[0];
4143+
const rightBtn = step.buttons[1];
40824144

40834145
card.innerHTML = html`
40844146
${dotsHtml}
@@ -4090,7 +4152,16 @@ function renderOnboardingStep(stepIndex) {
40904152
</div>
40914153
`;
40924154

4093-
applyOnboardingHighlight(step.highlight);
4155+
const backdrop = $('#onboarding-backdrop');
4156+
if (step.highlight) {
4157+
if (backdrop) backdrop.style.display = 'none';
4158+
applyOnboardingHighlight(step.highlight);
4159+
} else {
4160+
if (backdrop) backdrop.style.display = 'block';
4161+
clearOnboardingHighlight();
4162+
}
4163+
4164+
positionOnboardingCard(step.highlight);
40944165
initIcons();
40954166
}
40964167

@@ -4106,24 +4177,26 @@ async function startOnboarding() {
41064177
overlay.id = 'onboarding-overlay';
41074178
overlay.className = 'onboarding-overlay';
41084179
overlay.innerHTML = html`
4109-
<div class="onboarding-backdrop" id="onboarding-backdrop"></div>
4110-
<div class="onboarding-card" id="onboarding-card"></div>
4180+
<div class="onboarding-backdrop" id="onboarding-backdrop" style="display:none"></div>
4181+
<div class="onboarding-card centered" id="onboarding-card"></div>
41114182
`;
41124183
document.body.appendChild(overlay);
41134184

41144185
renderOnboardingStep(0);
41154186

4116-
$('#onboarding-skip').addEventListener('click', stopOnboarding);
4117-
$('#onboarding-next').addEventListener('click', () => {
4118-
if (onboardingStep === 0) {
4119-
onboardingStep = 1;
4120-
renderOnboardingStep(onboardingStep);
4121-
$('#onboarding-skip').addEventListener('click', stopOnboarding);
4122-
$('#onboarding-next').addEventListener('click', handleOnboardingNext);
4123-
} else {
4124-
handleOnboardingNext();
4125-
}
4126-
});
4187+
const attachListeners = () => {
4188+
$('#onboarding-skip').addEventListener('click', stopOnboarding);
4189+
$('#onboarding-next').addEventListener('click', () => {
4190+
if (onboardingStep === 0) {
4191+
onboardingStep = 1;
4192+
renderOnboardingStep(onboardingStep);
4193+
attachListeners();
4194+
} else {
4195+
handleOnboardingNext();
4196+
}
4197+
});
4198+
};
4199+
attachListeners();
41274200
}
41284201

41294202
function handleOnboardingNext() {

0 commit comments

Comments
 (0)