rails_onboarding 0.8.7 → 0.8.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5de350daba589470bba3cfa3afe9daa037307873d47a888f81899b2e542172fa
|
|
4
|
+
data.tar.gz: 6871219f6639948ec9e66747c2e89be3b58d2260d6ef8bc2750a84900db14b1d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2b6e4ccc57e00c7d41e4b21604be312330888ac2cc96e6b8ef0bc39206c529416ddc35f5d4bdc998632a6488fca0ce2a1c53e900c50115a17b08c17c2f9193f3
|
|
7
|
+
data.tar.gz: a4714eaed7cca529878cc9cc99ed06e0e48fa117a1cfa7f327eed5e9de97abf98cf5c35cc4ef7b51e2c8449cca5e78bf64953f9d2a8b2114487b60a9a0dc27d5
|
|
@@ -39,6 +39,7 @@ export default class extends Controller {
|
|
|
39
39
|
|
|
40
40
|
this.parseSteps()
|
|
41
41
|
this.setupKeyboardHandlers()
|
|
42
|
+
this.setupViewportHandlers()
|
|
42
43
|
|
|
43
44
|
// Auto-start if configured and not completed
|
|
44
45
|
if (this.autoStartValue && !this.isTourCompleted()) {
|
|
@@ -188,6 +189,9 @@ export default class extends Controller {
|
|
|
188
189
|
// Find target element
|
|
189
190
|
const targetElement = step.selector ? document.querySelector(step.selector) : null
|
|
190
191
|
|
|
192
|
+
this.currentTargetElement = targetElement
|
|
193
|
+
this.applyScrim(step, targetElement)
|
|
194
|
+
|
|
191
195
|
if (targetElement) {
|
|
192
196
|
this.scrollToElement(targetElement, step)
|
|
193
197
|
this.createHighlight(targetElement, step)
|
|
@@ -269,7 +273,7 @@ export default class extends Controller {
|
|
|
269
273
|
left: 0;
|
|
270
274
|
width: 100%;
|
|
271
275
|
height: 100%;
|
|
272
|
-
background:
|
|
276
|
+
background: transparent;
|
|
273
277
|
z-index: 9998;
|
|
274
278
|
opacity: 0;
|
|
275
279
|
transition: opacity 0.3s ease;
|
|
@@ -277,8 +281,12 @@ export default class extends Controller {
|
|
|
277
281
|
|
|
278
282
|
document.body.appendChild(this.overlay)
|
|
279
283
|
|
|
280
|
-
//
|
|
281
|
-
|
|
284
|
+
// Deliberately no `document.body.style.overflow = 'hidden'` here. The overlay is
|
|
285
|
+
// position:fixed and already covers the viewport, and locking the body made
|
|
286
|
+
// scrollToElement()'s window.scrollTo a no-op - so a target below the fold was
|
|
287
|
+
// spotlit off-screen, since the spotlight and popup are placed from
|
|
288
|
+
// getBoundingClientRect(). Scrolling stays live and repositionCurrentStep()
|
|
289
|
+
// keeps the highlight glued to its element instead.
|
|
282
290
|
|
|
283
291
|
// Trigger fade in
|
|
284
292
|
requestAnimationFrame(() => {
|
|
@@ -290,18 +298,15 @@ export default class extends Controller {
|
|
|
290
298
|
* Remove modal overlay
|
|
291
299
|
*/
|
|
292
300
|
removeOverlay() {
|
|
293
|
-
|
|
301
|
+
const overlay = this.overlay
|
|
302
|
+
if (!overlay) return
|
|
294
303
|
|
|
295
|
-
|
|
304
|
+
document.documentElement.style.removeProperty('--onboarding-tour-scrim')
|
|
305
|
+
this.overlay = null
|
|
306
|
+
overlay.style.opacity = '0'
|
|
296
307
|
|
|
297
308
|
setTimeout(() => {
|
|
298
|
-
if (
|
|
299
|
-
this.overlay.parentNode.removeChild(this.overlay)
|
|
300
|
-
}
|
|
301
|
-
this.overlay = null
|
|
302
|
-
|
|
303
|
-
// Restore body scroll
|
|
304
|
-
document.body.style.overflow = ''
|
|
309
|
+
if (overlay.parentNode) overlay.parentNode.removeChild(overlay)
|
|
305
310
|
}, 300)
|
|
306
311
|
}
|
|
307
312
|
|
|
@@ -336,7 +341,6 @@ export default class extends Controller {
|
|
|
336
341
|
left: ${rect.left - padding}px;
|
|
337
342
|
width: ${rect.width + (padding * 2)}px;
|
|
338
343
|
height: ${rect.height + (padding * 2)}px;
|
|
339
|
-
box-shadow: 0 0 0 9999px rgba(0, 0, 0, ${this.overlayOpacityValue});
|
|
340
344
|
border-radius: 8px;
|
|
341
345
|
`
|
|
342
346
|
break
|
|
@@ -372,11 +376,39 @@ export default class extends Controller {
|
|
|
372
376
|
|
|
373
377
|
document.body.appendChild(this.spotlight)
|
|
374
378
|
|
|
375
|
-
// Make highlighted element interactive
|
|
379
|
+
// Make highlighted element interactive, remembering what we overwrote so
|
|
380
|
+
// removeHighlight() can put it back without searching the document.
|
|
381
|
+
this.highlightedElement = element
|
|
382
|
+
this.previousElementPosition = element.style.position
|
|
383
|
+
this.previousElementZIndex = element.style.zIndex
|
|
376
384
|
element.style.position = 'relative'
|
|
377
385
|
element.style.zIndex = '10000'
|
|
378
386
|
}
|
|
379
387
|
|
|
388
|
+
/**
|
|
389
|
+
* Decide which layer paints the scrim for this step, and at what strength.
|
|
390
|
+
*
|
|
391
|
+
* A 'spotlight' highlight is already a full-viewport scrim - its box-shadow has a
|
|
392
|
+
* 9999px spread and covers everything but the cutout - so painting the overlay on
|
|
393
|
+
* top of it darkens every pixel twice. At the default 0.7 that composites to ~0.92,
|
|
394
|
+
* which buries the surrounding page and leaves someone unfamiliar with the layout
|
|
395
|
+
* with no idea what the highlight is being singled out *from*. Every other style
|
|
396
|
+
* (border, glow, none) draws no scrim of its own, and nor does a step with no target
|
|
397
|
+
* element, so those still need the overlay.
|
|
398
|
+
*/
|
|
399
|
+
applyScrim(step, targetElement) {
|
|
400
|
+
document.documentElement.style.setProperty(
|
|
401
|
+
'--onboarding-tour-scrim', this.overlayOpacityValue
|
|
402
|
+
)
|
|
403
|
+
|
|
404
|
+
if (!this.overlay) return
|
|
405
|
+
|
|
406
|
+
const spotlit = Boolean(targetElement) && step.highlightStyle === 'spotlight'
|
|
407
|
+
this.overlay.style.background = spotlit
|
|
408
|
+
? 'transparent'
|
|
409
|
+
: `rgba(0, 0, 0, ${this.overlayOpacityValue})`
|
|
410
|
+
}
|
|
411
|
+
|
|
380
412
|
/**
|
|
381
413
|
* Remove highlight/spotlight
|
|
382
414
|
*/
|
|
@@ -388,10 +420,14 @@ export default class extends Controller {
|
|
|
388
420
|
this.spotlight = null
|
|
389
421
|
}
|
|
390
422
|
|
|
391
|
-
//
|
|
392
|
-
document
|
|
393
|
-
|
|
394
|
-
|
|
423
|
+
// Restore only the element we actually touched. This used to sweep the whole
|
|
424
|
+
// document for [style*="z-index: 10000"], which clears the inline z-index of
|
|
425
|
+
// unrelated host-app elements that happen to carry that value.
|
|
426
|
+
if (this.highlightedElement) {
|
|
427
|
+
this.highlightedElement.style.position = this.previousElementPosition || ''
|
|
428
|
+
this.highlightedElement.style.zIndex = this.previousElementZIndex || ''
|
|
429
|
+
this.highlightedElement = null
|
|
430
|
+
}
|
|
395
431
|
}
|
|
396
432
|
|
|
397
433
|
/**
|
|
@@ -425,20 +461,20 @@ export default class extends Controller {
|
|
|
425
461
|
|
|
426
462
|
<div class="tour-popup-actions">
|
|
427
463
|
${step.showSkip ? `
|
|
428
|
-
<button type="button" class="tour-btn tour-btn-skip"
|
|
464
|
+
<button type="button" class="tour-btn tour-btn-skip">
|
|
429
465
|
${step.skipLabel}
|
|
430
466
|
</button>
|
|
431
467
|
` : '<div></div>'}
|
|
432
468
|
|
|
433
469
|
<div class="tour-popup-nav">
|
|
434
470
|
${step.showPrev && !isFirstStep ? `
|
|
435
|
-
<button type="button" class="tour-btn tour-btn-prev"
|
|
471
|
+
<button type="button" class="tour-btn tour-btn-prev">
|
|
436
472
|
← ${step.prevLabel}
|
|
437
473
|
</button>
|
|
438
474
|
` : ''}
|
|
439
475
|
|
|
440
476
|
${step.showNext ? `
|
|
441
|
-
<button type="button" class="tour-btn tour-btn-next"
|
|
477
|
+
<button type="button" class="tour-btn tour-btn-next">
|
|
442
478
|
${isLastStep ? step.completeLabel : step.nextLabel} →
|
|
443
479
|
</button>
|
|
444
480
|
` : ''}
|
|
@@ -452,32 +488,49 @@ export default class extends Controller {
|
|
|
452
488
|
|
|
453
489
|
document.body.appendChild(this.popup)
|
|
454
490
|
|
|
491
|
+
// The popup lives on document.body, so that host overflow and stacking
|
|
492
|
+
// contexts cannot clip it - which also puts it outside every controller
|
|
493
|
+
// scope, where Stimulus will not bind a data-action. These buttons are
|
|
494
|
+
// wired directly for that reason; a data-action on them would be silently
|
|
495
|
+
// inert, which is what left the tour unable to advance at all.
|
|
496
|
+
this.bindPopupActions()
|
|
497
|
+
|
|
455
498
|
// Position popup relative to target
|
|
456
499
|
this.positionPopup(step, targetElement)
|
|
457
500
|
|
|
458
501
|
// Animate in
|
|
459
502
|
requestAnimationFrame(() => {
|
|
460
|
-
this.popup.
|
|
461
|
-
this.popup.style.transform = 'scale(1)'
|
|
503
|
+
if (this.popup) this.popup.classList.add('onboarding-show')
|
|
462
504
|
})
|
|
463
505
|
}
|
|
464
506
|
|
|
507
|
+
/**
|
|
508
|
+
* Wire the popup's own controls. See the note in createPopup().
|
|
509
|
+
*/
|
|
510
|
+
bindPopupActions() {
|
|
511
|
+
const actions = {
|
|
512
|
+
'.tour-btn-next': () => this.next(),
|
|
513
|
+
'.tour-btn-prev': () => this.previous(),
|
|
514
|
+
'.tour-btn-skip': () => this.skip()
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
for (const [selector, handler] of Object.entries(actions)) {
|
|
518
|
+
this.popup.querySelector(selector)?.addEventListener('click', (event) => {
|
|
519
|
+
event.preventDefault()
|
|
520
|
+
handler()
|
|
521
|
+
})
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
465
525
|
/**
|
|
466
526
|
* Style the popup element
|
|
467
527
|
*/
|
|
468
528
|
stylePopup(step) {
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
|
475
|
-
max-width: ${step.width}px;
|
|
476
|
-
width: calc(100% - 2rem);
|
|
477
|
-
opacity: 0;
|
|
478
|
-
transform: scale(0.95);
|
|
479
|
-
transition: all 0.3s ease;
|
|
480
|
-
`
|
|
529
|
+
// Only the per-step width is set inline. Everything else - including the
|
|
530
|
+
// background - belongs to `.tour-popup` in tour.css, so that a host app
|
|
531
|
+
// redefining the --onboarding-* tokens (and the dark-mode block that flips
|
|
532
|
+
// them) actually reaches the popup. An inline background would win over both.
|
|
533
|
+
this.popup.style.maxWidth = `${step.width}px`
|
|
481
534
|
}
|
|
482
535
|
|
|
483
536
|
/**
|
|
@@ -569,17 +622,19 @@ export default class extends Controller {
|
|
|
569
622
|
* Remove popup
|
|
570
623
|
*/
|
|
571
624
|
removePopup() {
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
this.popup.style.transform = 'scale(0.95)'
|
|
625
|
+
const popup = this.popup
|
|
626
|
+
if (!popup) return
|
|
575
627
|
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
628
|
+
// Detach from the instance up front and let the timeout close over the local.
|
|
629
|
+
// createPopup() calls removePopup() and then assigns a new this.popup straight
|
|
630
|
+
// away, so a timeout reading the instance property would remove the popup that
|
|
631
|
+
// replaced this one - every Next and Previous would blank the tour after 300ms.
|
|
632
|
+
this.popup = null
|
|
633
|
+
popup.classList.remove('onboarding-show')
|
|
634
|
+
|
|
635
|
+
setTimeout(() => {
|
|
636
|
+
if (popup.parentNode) popup.parentNode.removeChild(popup)
|
|
637
|
+
}, 300)
|
|
583
638
|
}
|
|
584
639
|
|
|
585
640
|
/**
|
|
@@ -623,6 +678,38 @@ export default class extends Controller {
|
|
|
623
678
|
}
|
|
624
679
|
}
|
|
625
680
|
|
|
681
|
+
/**
|
|
682
|
+
* Re-place the highlight and popup for the current step. The spotlight and popup
|
|
683
|
+
* are position:fixed and derived from getBoundingClientRect(), so they have to be
|
|
684
|
+
* recomputed whenever the viewport moves under them.
|
|
685
|
+
*/
|
|
686
|
+
repositionCurrentStep() {
|
|
687
|
+
if (!this.isActive) return
|
|
688
|
+
|
|
689
|
+
const step = this.tourSteps[this.currentStepIndex]
|
|
690
|
+
if (!step) return
|
|
691
|
+
|
|
692
|
+
const element = this.currentTargetElement
|
|
693
|
+
if (element && element.isConnected) {
|
|
694
|
+
this.createHighlight(element, step)
|
|
695
|
+
}
|
|
696
|
+
this.positionPopup(step, element)
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* Setup viewport handlers that keep the current step aligned
|
|
701
|
+
*/
|
|
702
|
+
setupViewportHandlers() {
|
|
703
|
+
this.viewportHandler = () => {
|
|
704
|
+
if (!this.isActive) return
|
|
705
|
+
if (this.viewportFrame) cancelAnimationFrame(this.viewportFrame)
|
|
706
|
+
this.viewportFrame = requestAnimationFrame(() => this.repositionCurrentStep())
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
window.addEventListener('scroll', this.viewportHandler, { passive: true })
|
|
710
|
+
window.addEventListener('resize', this.viewportHandler)
|
|
711
|
+
}
|
|
712
|
+
|
|
626
713
|
/**
|
|
627
714
|
* Setup keyboard event handlers
|
|
628
715
|
*/
|
|
@@ -759,5 +846,12 @@ export default class extends Controller {
|
|
|
759
846
|
if (this.keyboardHandler) {
|
|
760
847
|
document.removeEventListener('keydown', this.keyboardHandler)
|
|
761
848
|
}
|
|
849
|
+
|
|
850
|
+
if (this.viewportHandler) {
|
|
851
|
+
window.removeEventListener('scroll', this.viewportHandler)
|
|
852
|
+
window.removeEventListener('resize', this.viewportHandler)
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
if (this.viewportFrame) cancelAnimationFrame(this.viewportFrame)
|
|
762
856
|
}
|
|
763
857
|
}
|
|
@@ -22,60 +22,56 @@
|
|
|
22
22
|
border-radius: 8px;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
/* Spotlight style - Creates cutout effect
|
|
25
|
+
/* Spotlight style - Creates cutout effect.
|
|
26
|
+
The 9999px spread makes this box-shadow a full-viewport scrim in its own right, so
|
|
27
|
+
tour_controller stops painting .tour-overlay whenever a spotlight is drawn - the two
|
|
28
|
+
together composited to ~0.92 and buried the surrounding page.
|
|
29
|
+
The alpha comes from --onboarding-tour-scrim, which the controller sets on :root from
|
|
30
|
+
its overlayOpacity value. It is deliberately not animated: an animation on this
|
|
31
|
+
property overrides the inline style, which is what made overlayOpacity a dead knob. */
|
|
26
32
|
.tour-spotlight-spotlight {
|
|
27
|
-
box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.7);
|
|
28
|
-
animation: onboarding-spotlightPulse 2s ease-in-out infinite;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
@keyframes onboarding-spotlightPulse {
|
|
32
|
-
0%, 100% {
|
|
33
|
-
box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.7);
|
|
34
|
-
}
|
|
35
|
-
50% {
|
|
36
|
-
box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.75);
|
|
37
|
-
}
|
|
33
|
+
box-shadow: 0 0 0 9999px rgba(0, 0, 0, var(--onboarding-tour-scrim, 0.7));
|
|
38
34
|
}
|
|
39
35
|
|
|
40
36
|
/* Border highlight style */
|
|
41
37
|
.tour-spotlight-border {
|
|
42
|
-
border: 3px solid
|
|
43
|
-
box-shadow: 0 0 0 4px
|
|
38
|
+
border: 3px solid var(--onboarding-primary);
|
|
39
|
+
box-shadow: 0 0 0 4px color-mix(in srgb, var(--onboarding-primary) 20%, transparent);
|
|
44
40
|
animation: onboarding-borderPulse 2s ease-in-out infinite;
|
|
45
41
|
}
|
|
46
42
|
|
|
47
43
|
@keyframes onboarding-borderPulse {
|
|
48
44
|
0%, 100% {
|
|
49
|
-
border-color:
|
|
50
|
-
box-shadow: 0 0 0 4px
|
|
45
|
+
border-color: var(--onboarding-primary);
|
|
46
|
+
box-shadow: 0 0 0 4px color-mix(in srgb, var(--onboarding-primary) 20%, transparent);
|
|
51
47
|
}
|
|
52
48
|
50% {
|
|
53
|
-
border-color:
|
|
54
|
-
box-shadow: 0 0 0 6px
|
|
49
|
+
border-color: var(--onboarding-primary-hover);
|
|
50
|
+
box-shadow: 0 0 0 6px color-mix(in srgb, var(--onboarding-primary-hover) 30%, transparent);
|
|
55
51
|
}
|
|
56
52
|
}
|
|
57
53
|
|
|
58
54
|
/* Glow highlight style */
|
|
59
55
|
.tour-spotlight-glow {
|
|
60
56
|
box-shadow:
|
|
61
|
-
0 0 0 4px
|
|
62
|
-
0 0 20px 8px
|
|
63
|
-
inset 0 0 20px
|
|
57
|
+
0 0 0 4px color-mix(in srgb, var(--onboarding-primary) 30%, transparent),
|
|
58
|
+
0 0 20px 8px color-mix(in srgb, var(--onboarding-primary) 40%, transparent),
|
|
59
|
+
inset 0 0 20px color-mix(in srgb, var(--onboarding-primary) 20%, transparent);
|
|
64
60
|
animation: onboarding-glowPulse 2s ease-in-out infinite;
|
|
65
61
|
}
|
|
66
62
|
|
|
67
63
|
@keyframes onboarding-glowPulse {
|
|
68
64
|
0%, 100% {
|
|
69
65
|
box-shadow:
|
|
70
|
-
0 0 0 4px
|
|
71
|
-
0 0 20px 8px
|
|
72
|
-
inset 0 0 20px
|
|
66
|
+
0 0 0 4px color-mix(in srgb, var(--onboarding-primary) 30%, transparent),
|
|
67
|
+
0 0 20px 8px color-mix(in srgb, var(--onboarding-primary) 40%, transparent),
|
|
68
|
+
inset 0 0 20px color-mix(in srgb, var(--onboarding-primary) 20%, transparent);
|
|
73
69
|
}
|
|
74
70
|
50% {
|
|
75
71
|
box-shadow:
|
|
76
|
-
0 0 0 6px
|
|
77
|
-
0 0 30px 12px
|
|
78
|
-
inset 0 0 30px
|
|
72
|
+
0 0 0 6px color-mix(in srgb, var(--onboarding-primary) 40%, transparent),
|
|
73
|
+
0 0 30px 12px color-mix(in srgb, var(--onboarding-primary) 50%, transparent),
|
|
74
|
+
inset 0 0 30px color-mix(in srgb, var(--onboarding-primary) 30%, transparent);
|
|
79
75
|
}
|
|
80
76
|
}
|
|
81
77
|
|
|
@@ -83,7 +79,9 @@
|
|
|
83
79
|
.tour-popup {
|
|
84
80
|
position: fixed;
|
|
85
81
|
z-index: 10001;
|
|
86
|
-
background:
|
|
82
|
+
background: var(--onboarding-surface-elevated);
|
|
83
|
+
color: var(--onboarding-text);
|
|
84
|
+
border: 1px solid var(--onboarding-border);
|
|
87
85
|
border-radius: 12px;
|
|
88
86
|
box-shadow:
|
|
89
87
|
0 20px 25px -5px rgba(0, 0, 0, 0.1),
|
|
@@ -110,7 +108,7 @@
|
|
|
110
108
|
margin: 0 0 1rem;
|
|
111
109
|
font-size: 1.25rem;
|
|
112
110
|
font-weight: 600;
|
|
113
|
-
color:
|
|
111
|
+
color: var(--onboarding-text);
|
|
114
112
|
line-height: 1.4;
|
|
115
113
|
}
|
|
116
114
|
|
|
@@ -119,7 +117,7 @@
|
|
|
119
117
|
margin: 0 0 1.5rem;
|
|
120
118
|
font-size: 0.9375rem;
|
|
121
119
|
line-height: 1.6;
|
|
122
|
-
color:
|
|
120
|
+
color: var(--onboarding-text-muted);
|
|
123
121
|
}
|
|
124
122
|
|
|
125
123
|
.tour-popup-body p {
|
|
@@ -142,12 +140,12 @@
|
|
|
142
140
|
|
|
143
141
|
.tour-popup-body strong {
|
|
144
142
|
font-weight: 600;
|
|
145
|
-
color:
|
|
143
|
+
color: var(--onboarding-text);
|
|
146
144
|
}
|
|
147
145
|
|
|
148
146
|
.tour-popup-body code {
|
|
149
147
|
padding: 0.125rem 0.375rem;
|
|
150
|
-
background:
|
|
148
|
+
background: var(--onboarding-surface);
|
|
151
149
|
border-radius: 0.25rem;
|
|
152
150
|
font-family: 'Monaco', 'Menlo', 'Courier New', monospace;
|
|
153
151
|
font-size: 0.875em;
|
|
@@ -157,14 +155,14 @@
|
|
|
157
155
|
.tour-popup-progress {
|
|
158
156
|
margin: 1.5rem 0 1rem;
|
|
159
157
|
padding-top: 1rem;
|
|
160
|
-
border-top: 1px solid
|
|
158
|
+
border-top: 1px solid var(--onboarding-border);
|
|
161
159
|
}
|
|
162
160
|
|
|
163
161
|
/* Progress Bar */
|
|
164
162
|
.tour-progress-bar {
|
|
165
163
|
width: 100%;
|
|
166
164
|
height: 6px;
|
|
167
|
-
background:
|
|
165
|
+
background: var(--onboarding-border);
|
|
168
166
|
border-radius: 3px;
|
|
169
167
|
overflow: hidden;
|
|
170
168
|
margin-bottom: 0.5rem;
|
|
@@ -172,7 +170,7 @@
|
|
|
172
170
|
|
|
173
171
|
.tour-progress-fill {
|
|
174
172
|
height: 100%;
|
|
175
|
-
background: linear-gradient(90deg,
|
|
173
|
+
background: linear-gradient(90deg, var(--onboarding-primary-fill), var(--onboarding-primary-fill-hover));
|
|
176
174
|
border-radius: 3px;
|
|
177
175
|
transition: width 0.3s ease;
|
|
178
176
|
}
|
|
@@ -180,7 +178,7 @@
|
|
|
180
178
|
/* Progress Text */
|
|
181
179
|
.tour-progress-text {
|
|
182
180
|
font-size: 0.8125rem;
|
|
183
|
-
color:
|
|
181
|
+
color: var(--onboarding-text-muted);
|
|
184
182
|
text-align: center;
|
|
185
183
|
font-weight: 500;
|
|
186
184
|
}
|
|
@@ -217,7 +215,7 @@
|
|
|
217
215
|
|
|
218
216
|
.tour-btn:focus {
|
|
219
217
|
outline: none;
|
|
220
|
-
box-shadow:
|
|
218
|
+
box-shadow: var(--onboarding-focus-ring);
|
|
221
219
|
}
|
|
222
220
|
|
|
223
221
|
.tour-btn:active {
|
|
@@ -226,47 +224,47 @@
|
|
|
226
224
|
|
|
227
225
|
/* Next Button - Primary */
|
|
228
226
|
.tour-btn-next {
|
|
229
|
-
background:
|
|
230
|
-
color:
|
|
227
|
+
background: var(--onboarding-primary-fill);
|
|
228
|
+
color: var(--onboarding-on-primary);
|
|
231
229
|
padding: 0.625rem 1.25rem;
|
|
232
230
|
}
|
|
233
231
|
|
|
234
232
|
.tour-btn-next:hover {
|
|
235
|
-
background:
|
|
233
|
+
background: var(--onboarding-primary-fill-hover);
|
|
236
234
|
}
|
|
237
235
|
|
|
238
236
|
.tour-btn-next:active {
|
|
239
|
-
background:
|
|
237
|
+
background: var(--onboarding-primary-fill-hover);
|
|
240
238
|
}
|
|
241
239
|
|
|
242
240
|
/* Previous Button - Secondary */
|
|
243
241
|
.tour-btn-prev {
|
|
244
|
-
background:
|
|
245
|
-
color:
|
|
242
|
+
background: var(--onboarding-surface);
|
|
243
|
+
color: var(--onboarding-text);
|
|
246
244
|
}
|
|
247
245
|
|
|
248
246
|
.tour-btn-prev:hover {
|
|
249
|
-
background:
|
|
247
|
+
background: var(--onboarding-border);
|
|
250
248
|
}
|
|
251
249
|
|
|
252
250
|
.tour-btn-prev:active {
|
|
253
|
-
background:
|
|
251
|
+
background: var(--onboarding-border);
|
|
254
252
|
}
|
|
255
253
|
|
|
256
254
|
/* Skip Button - Ghost */
|
|
257
255
|
.tour-btn-skip {
|
|
258
256
|
background: transparent;
|
|
259
|
-
color:
|
|
257
|
+
color: var(--onboarding-text-muted);
|
|
260
258
|
padding: 0.5rem 0.75rem;
|
|
261
259
|
}
|
|
262
260
|
|
|
263
261
|
.tour-btn-skip:hover {
|
|
264
|
-
color:
|
|
265
|
-
background:
|
|
262
|
+
color: var(--onboarding-text);
|
|
263
|
+
background: var(--onboarding-surface);
|
|
266
264
|
}
|
|
267
265
|
|
|
268
266
|
.tour-btn-skip:active {
|
|
269
|
-
background:
|
|
267
|
+
background: var(--onboarding-border);
|
|
270
268
|
}
|
|
271
269
|
|
|
272
270
|
/* Mobile Responsive */
|
|
@@ -325,16 +323,20 @@
|
|
|
325
323
|
background: rgba(0, 0, 0, 0.85);
|
|
326
324
|
}
|
|
327
325
|
|
|
326
|
+
.tour-spotlight-spotlight {
|
|
327
|
+
--onboarding-tour-scrim: 0.85;
|
|
328
|
+
}
|
|
329
|
+
|
|
328
330
|
.tour-spotlight-border {
|
|
329
331
|
border-width: 4px;
|
|
330
332
|
}
|
|
331
333
|
|
|
332
334
|
.tour-btn-next {
|
|
333
|
-
background:
|
|
335
|
+
background: var(--onboarding-primary-fill-hover);
|
|
334
336
|
}
|
|
335
337
|
|
|
336
338
|
.tour-btn-prev {
|
|
337
|
-
border: 2px solid
|
|
339
|
+
border: 2px solid var(--onboarding-border);
|
|
338
340
|
}
|
|
339
341
|
}
|
|
340
342
|
|
|
@@ -349,10 +351,6 @@
|
|
|
349
351
|
animation: none;
|
|
350
352
|
}
|
|
351
353
|
|
|
352
|
-
.tour-spotlight-spotlight {
|
|
353
|
-
animation: none;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
354
|
.tour-spotlight-border {
|
|
357
355
|
animation: none;
|
|
358
356
|
}
|
|
@@ -362,63 +360,6 @@
|
|
|
362
360
|
}
|
|
363
361
|
}
|
|
364
362
|
|
|
365
|
-
/* Dark Mode Support */
|
|
366
|
-
@media (prefers-color-scheme: dark) {
|
|
367
|
-
.tour-popup {
|
|
368
|
-
background: #1f2937;
|
|
369
|
-
box-shadow:
|
|
370
|
-
0 20px 25px -5px rgba(0, 0, 0, 0.3),
|
|
371
|
-
0 10px 10px -5px rgba(0, 0, 0, 0.2);
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
.tour-popup-title {
|
|
375
|
-
color: #f9fafb;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
.tour-popup-body {
|
|
379
|
-
color: #d1d5db;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
.tour-popup-body strong {
|
|
383
|
-
color: #f3f4f6;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
.tour-popup-body code {
|
|
387
|
-
background: #374151;
|
|
388
|
-
color: #e5e7eb;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
.tour-popup-progress {
|
|
392
|
-
border-top-color: #374151;
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
.tour-progress-bar {
|
|
396
|
-
background: #374151;
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
.tour-progress-text {
|
|
400
|
-
color: #9ca3af;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
.tour-btn-prev {
|
|
404
|
-
background: #374151;
|
|
405
|
-
color: #e5e7eb;
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
.tour-btn-prev:hover {
|
|
409
|
-
background: #4b5563;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
.tour-btn-skip {
|
|
413
|
-
color: #9ca3af;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
.tour-btn-skip:hover {
|
|
417
|
-
color: #d1d5db;
|
|
418
|
-
background: #374151;
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
|
|
422
363
|
/* Print Styles - Hide tour elements when printing */
|
|
423
364
|
@media print {
|
|
424
365
|
.tour-overlay,
|
|
@@ -434,13 +375,13 @@
|
|
|
434
375
|
}
|
|
435
376
|
|
|
436
377
|
.tour-btn:focus-visible {
|
|
437
|
-
box-shadow:
|
|
378
|
+
box-shadow: var(--onboarding-focus-ring);
|
|
438
379
|
}
|
|
439
380
|
|
|
440
381
|
/* Utility classes for custom tour content */
|
|
441
382
|
.tour-highlight {
|
|
442
|
-
background:
|
|
443
|
-
color:
|
|
383
|
+
background: color-mix(in srgb, var(--onboarding-primary-fill) 18%, transparent);
|
|
384
|
+
color: var(--onboarding-text);
|
|
444
385
|
padding: 0.125rem 0.375rem;
|
|
445
386
|
border-radius: 0.25rem;
|
|
446
387
|
font-weight: 500;
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rails_onboarding
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.8.
|
|
4
|
+
version: 0.8.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- David Lewis
|
|
@@ -282,7 +282,7 @@ licenses:
|
|
|
282
282
|
metadata:
|
|
283
283
|
allowed_push_host: https://rubygems.org
|
|
284
284
|
homepage_uri: https://github.com/bunnahabhain/rails_onboarding
|
|
285
|
-
source_code_uri: https://github.com/bunnahabhain/rails_onboarding/tree/v0.8.
|
|
285
|
+
source_code_uri: https://github.com/bunnahabhain/rails_onboarding/tree/v0.8.9
|
|
286
286
|
changelog_uri: https://github.com/bunnahabhain/rails_onboarding/blob/master/docs/CHANGELOG.md
|
|
287
287
|
rdoc_options: []
|
|
288
288
|
require_paths:
|
|
@@ -298,7 +298,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
298
298
|
- !ruby/object:Gem::Version
|
|
299
299
|
version: '0'
|
|
300
300
|
requirements: []
|
|
301
|
-
rubygems_version: 4.0.
|
|
301
|
+
rubygems_version: 4.0.19
|
|
302
302
|
specification_version: 4
|
|
303
303
|
summary: Flexible onboarding engine for Rails applications
|
|
304
304
|
test_files: []
|