|
317 | 317 | </style> |
318 | 318 |
|
319 | 319 | <script> |
| 320 | + // TypeScript declaration for Plausible |
| 321 | + declare global { |
| 322 | + interface Window { |
| 323 | + plausible?: (event: string, options?: { props?: Record<string, string | number> }) => void; |
| 324 | + } |
| 325 | + } |
| 326 | + |
320 | 327 | // Global flag to track if auto-scroll animation is running |
321 | 328 | let isAutoScrolling = false; |
322 | 329 |
|
| 330 | + // Flag to track if programmatic scroll is happening (auto-scroll or scroll-to-top) |
| 331 | + let isProgrammaticScroll = false; |
| 332 | + |
| 333 | + // Flag to track if manual scroll event has been sent (only send once) |
| 334 | + let hasTrackedManualScroll = false; |
| 335 | + |
323 | 336 | const handleRevealButton = () => { |
324 | 337 | const button = document.querySelector('.reveal-button') as HTMLElement | null; |
325 | 338 | const overlay = document.querySelector('.code-overlay') as HTMLElement | null; |
|
329 | 342 | if (!button || !overlay || !scrollableContainer || !scrollableInner) return; |
330 | 343 |
|
331 | 344 | button.addEventListener('click', async () => { |
| 345 | + // Track custom event in Plausible |
| 346 | + if (typeof window.plausible !== 'undefined') { |
| 347 | + window.plausible('home:reveal-code'); |
| 348 | + } |
| 349 | + |
332 | 350 | const wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); |
333 | 351 |
|
334 | 352 | // Helper to animate scroll with custom duration (cancellable on user interaction) |
|
445 | 463 | return; |
446 | 464 | } |
447 | 465 |
|
| 466 | + // Track manual scroll event (only once, and only if not programmatic) |
| 467 | + if (!hasTrackedManualScroll && !isProgrammaticScroll) { |
| 468 | + hasTrackedManualScroll = true; |
| 469 | + if (typeof window.plausible !== 'undefined') { |
| 470 | + window.plausible('home:code-scroll'); |
| 471 | + } |
| 472 | + } |
| 473 | + |
448 | 474 | if (scrollableInner.scrollTop > 50) { |
449 | 475 | button.style.display = 'block'; |
450 | 476 | } else { |
|
456 | 482 | scrollableInner.addEventListener('scroll', updateButtonVisibility); |
457 | 483 |
|
458 | 484 | button.addEventListener('click', () => { |
| 485 | + // Mark as programmatic scroll to avoid tracking |
| 486 | + isProgrammaticScroll = true; |
459 | 487 | scrollableInner.scrollTo({ top: 0, behavior: 'smooth' }); |
| 488 | + |
| 489 | + // Reset flag after scroll completes |
| 490 | + setTimeout(() => { |
| 491 | + isProgrammaticScroll = false; |
| 492 | + }, 1000); |
460 | 493 | }); |
461 | 494 | }; |
462 | 495 |
|
|
480 | 513 | if (scrollTopButton) { |
481 | 514 | scrollTopButton.style.display = 'none'; |
482 | 515 | } |
| 516 | + |
| 517 | + // Note: hasTrackedManualScroll is NOT reset here |
| 518 | + // This means we track manual scroll only once per page session, |
| 519 | + // even if user reveals, resets, and reveals again |
483 | 520 | }); |
484 | 521 | }; |
485 | 522 |
|
|
0 commit comments