Spaces:
Paused
Paused
Download docs/src/theme/Root.js from Leon4gr45/powerbi: direct link, hf CLI and curl.
- Browser
- Download file 12.7 kB
-
https://huggingface.co/spaces/Leon4gr45/powerbi/resolve/main/docs/src/theme/Root.js
- Command line
-
hf download hf://spaces/Leon4gr45/powerbi/docs/src/theme/Root.js
-
curl -L -o Root.js https://huggingface.co/spaces/Leon4gr45/powerbi/resolve/main/docs/src/theme/Root.js
12.7 kB
| /** | |
| * Licensed to the Apache Software Foundation (ASF) under one | |
| * or more contributor license agreements. See the NOTICE file | |
| * distributed with this work for additional information | |
| * regarding copyright ownership. The ASF licenses this file | |
| * to you under the Apache License, Version 2.0 (the | |
| * "License"); you may not use this file except in compliance | |
| * with the License. You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, | |
| * software distributed under the License is distributed on an | |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| * KIND, either express or implied. See the License for the | |
| * specific language governing permissions and limitations | |
| * under the License. | |
| */ | |
| import { useEffect } from 'react'; | |
| import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; | |
| // File extensions to track as downloads | |
| const DOWNLOAD_EXTENSIONS = [ | |
| 'pdf', | |
| 'zip', | |
| 'tar', | |
| 'gz', | |
| 'tgz', | |
| 'bz2', | |
| 'exe', | |
| 'dmg', | |
| 'pkg', | |
| 'deb', | |
| 'rpm', | |
| 'doc', | |
| 'docx', | |
| 'xls', | |
| 'xlsx', | |
| 'ppt', | |
| 'pptx', | |
| 'csv', | |
| 'json', | |
| 'yaml', | |
| 'yml', | |
| ]; | |
| // Scroll depth milestones to track | |
| const SCROLL_MILESTONES = [25, 50, 75, 100]; | |
| export default function Root({ children }) { | |
| const { siteConfig } = useDocusaurusContext(); | |
| const { customFields } = siteConfig; | |
| useEffect(() => { | |
| const { matomoUrl, matomoSiteId } = customFields; | |
| if (typeof window !== 'undefined') { | |
| const devMode = ['localhost', '127.0.0.1', '::1', '0.0.0.0'].includes( | |
| window.location.hostname, | |
| ); | |
| // Initialize the _paq array | |
| window._paq = window._paq || []; | |
| // Configure the tracker before loading matomo.js | |
| window._paq.push(['enableHeartBeatTimer']); | |
| window._paq.push(['enableLinkTracking']); | |
| window._paq.push(['setTrackerUrl', `${matomoUrl}/matomo.php`]); | |
| window._paq.push(['setSiteId', matomoSiteId]); | |
| // Track downloads with custom extensions | |
| window._paq.push([ | |
| 'setDownloadExtensions', | |
| DOWNLOAD_EXTENSIONS.join('|'), | |
| ]); | |
| // Now load the matomo.js script | |
| const script = document.createElement('script'); | |
| script.async = true; | |
| script.src = `${matomoUrl}/matomo.js`; | |
| document.head.appendChild(script); | |
| // Helper to track events | |
| const trackEvent = (category, action, name, value) => { | |
| if (devMode) { | |
| console.log('Matomo trackEvent:', { category, action, name, value }); | |
| } | |
| window._paq.push(['trackEvent', category, action, name, value]); | |
| }; | |
| // Helper to track site search | |
| const trackSiteSearch = (keyword, category, resultsCount) => { | |
| if (devMode) { | |
| console.log('Matomo trackSiteSearch:', { | |
| keyword, | |
| category, | |
| resultsCount, | |
| }); | |
| } | |
| window._paq.push(['trackSiteSearch', keyword, category, resultsCount]); | |
| }; | |
| // Helper to track page views | |
| const trackPageView = (url, title) => { | |
| if (devMode) { | |
| console.log('Matomo trackPageView:', { url, title }); | |
| } | |
| window._paq.push(['trackPageView']); | |
| }; | |
| // Track external link clicks using domain as category (vendor-agnostic) | |
| const handleLinkClick = event => { | |
| const link = event.target.closest('a'); | |
| if (!link) return; | |
| const href = link.getAttribute('href'); | |
| if (!href) return; | |
| try { | |
| const url = new URL(href, window.location.origin); | |
| // Skip internal links | |
| if (url.hostname === window.location.hostname) return; | |
| // Use hostname as category for vendor-agnostic tracking | |
| trackEvent('Outbound Link', url.hostname, href); | |
| } catch { | |
| // Invalid URL, skip tracking | |
| } | |
| }; | |
| // Track Algolia search queries | |
| const setupAlgoliaTracking = () => { | |
| const observer = new MutationObserver(mutations => { | |
| mutations.forEach(mutation => { | |
| mutation.addedNodes.forEach(node => { | |
| if (node.nodeType === Node.ELEMENT_NODE) { | |
| const searchInput = | |
| node.querySelector?.('.DocSearch-Input') || | |
| (node.classList?.contains('DocSearch-Input') ? node : null); | |
| if (searchInput) { | |
| let debounceTimer; | |
| searchInput.addEventListener('input', e => { | |
| clearTimeout(debounceTimer); | |
| debounceTimer = setTimeout(() => { | |
| const query = e.target.value.trim(); | |
| if (query.length >= 3) { | |
| const results = | |
| document.querySelectorAll('.DocSearch-Hit'); | |
| trackSiteSearch(query, 'Documentation', results.length); | |
| } | |
| }, 1000); | |
| }); | |
| } | |
| } | |
| }); | |
| }); | |
| }); | |
| observer.observe(document.body, { childList: true, subtree: true }); | |
| return observer; | |
| }; | |
| // Track video plays | |
| const handleVideoPlay = event => { | |
| if (event.target.tagName === 'VIDEO') { | |
| const videoSrc = | |
| event.target.currentSrc || event.target.src || 'unknown'; | |
| trackEvent('Video', 'Play', videoSrc); | |
| } | |
| }; | |
| // Track CTA button clicks | |
| const handleCTAClick = event => { | |
| const button = event.target.closest( | |
| '.get-started-button, .default-button-theme', | |
| ); | |
| if (button) { | |
| const buttonText = button.textContent?.trim() || 'Unknown'; | |
| const clickedLink = event.target.closest?.('a'); | |
| const href = | |
| clickedLink?.getAttribute('href') || | |
| button.getAttribute('href') || | |
| ''; | |
| trackEvent('CTA', 'Click', `${buttonText} - ${href}`); | |
| } | |
| }; | |
| // Track scroll depth | |
| let scrollMilestonesReached = new Set(); | |
| const handleScroll = () => { | |
| const scrollTop = window.scrollY; | |
| const docHeight = | |
| document.documentElement.scrollHeight - window.innerHeight; | |
| if (docHeight <= 0) return; | |
| const scrollPercent = Math.round((scrollTop / docHeight) * 100); | |
| SCROLL_MILESTONES.forEach(milestone => { | |
| if ( | |
| scrollPercent >= milestone && | |
| !scrollMilestonesReached.has(milestone) | |
| ) { | |
| scrollMilestonesReached.add(milestone); | |
| trackEvent( | |
| 'Scroll Depth', | |
| `${milestone}%`, | |
| window.location.pathname, | |
| ); | |
| } | |
| }); | |
| }; | |
| // Reset scroll tracking on route change | |
| const resetScrollTracking = () => { | |
| scrollMilestonesReached = new Set(); | |
| }; | |
| // Track 404 pages | |
| const track404 = () => { | |
| const is404 = | |
| document.querySelector('.theme-doc-404') || | |
| document.title.toLowerCase().includes('not found') || | |
| document | |
| .querySelector('h1') | |
| ?.textContent?.toLowerCase() | |
| .includes('not found'); | |
| if (is404) { | |
| trackEvent('Error', '404', window.location.pathname); | |
| if (devMode) { | |
| console.log('Matomo: 404 page detected', window.location.pathname); | |
| } | |
| } | |
| }; | |
| // Track copy-to-clipboard events on code blocks | |
| const handleCopy = event => { | |
| const codeBlock = event.target.closest('pre, code, .prism-code'); | |
| if (codeBlock) { | |
| const codeText = window.getSelection()?.toString() || ''; | |
| const codeSnippet = | |
| codeText.substring(0, 100) + (codeText.length > 100 ? '...' : ''); | |
| trackEvent( | |
| 'Code', | |
| 'Copy', | |
| `${window.location.pathname}: ${codeSnippet}`, | |
| ); | |
| } | |
| }; | |
| // Track color mode preference (as event, no admin config needed) | |
| const trackColorMode = () => { | |
| const colorMode = | |
| document.documentElement.getAttribute('data-theme') || | |
| (window.matchMedia('(prefers-color-scheme: dark)').matches | |
| ? 'dark' | |
| : 'light'); | |
| trackEvent('User Preference', 'Color Mode', colorMode); | |
| }; | |
| // Track docs version from URL (as event, no admin config needed) | |
| const trackDocsVersion = () => { | |
| const pathMatch = window.location.pathname.match(/\/docs\/([\d.]+)\//); | |
| const version = pathMatch ? pathMatch[1] : 'latest'; | |
| trackEvent('User Preference', 'Docs Version', version); | |
| }; | |
| // Handle route changes for SPA | |
| const handleRouteChange = () => { | |
| if (devMode) { | |
| console.log('Route changed to:', window.location.pathname); | |
| } | |
| // Reset scroll tracking for new page | |
| resetScrollTracking(); | |
| setTimeout(() => { | |
| const currentTitle = document.title; | |
| const currentPath = window.location.pathname; | |
| // Set custom dimensions before tracking page view | |
| trackColorMode(); | |
| trackDocsVersion(); | |
| if (devMode) { | |
| window._paq.push(['setDomains', ['superset.apache.org']]); | |
| window._paq.push([ | |
| 'setCustomUrl', | |
| 'https://superset.apache.org' + currentPath, | |
| ]); | |
| } else { | |
| window._paq.push(['setCustomUrl', currentPath]); | |
| } | |
| window._paq.push(['setReferrerUrl', window.location.href]); | |
| window._paq.push(['setDocumentTitle', currentTitle]); | |
| trackPageView(currentPath, currentTitle); | |
| // Check for 404 after page renders | |
| setTimeout(track404, 500); | |
| }, 100); | |
| }; | |
| // Set up Docusaurus route listeners | |
| const possibleEvents = [ | |
| 'docusaurus.routeDidUpdate', | |
| 'docusaurusRouteDidUpdate', | |
| 'routeDidUpdate', | |
| ]; | |
| if (devMode) { | |
| console.log('Setting up Matomo tracking with enhanced features'); | |
| } | |
| // Store handler references for proper cleanup | |
| const routeHandlers = possibleEvents.map(eventName => { | |
| const handler = () => { | |
| if (devMode) { | |
| console.log(`Docusaurus route update detected via ${eventName}`); | |
| } | |
| handleRouteChange(); | |
| }; | |
| document.addEventListener(eventName, handler); | |
| return { eventName, handler }; | |
| }); | |
| // Manual history tracking as fallback | |
| const originalPushState = window.history.pushState; | |
| window.history.pushState = function () { | |
| originalPushState.apply(this, arguments); | |
| handleRouteChange(); | |
| }; | |
| window.addEventListener('popstate', handleRouteChange); | |
| // Set up event listeners | |
| document.addEventListener('click', handleLinkClick); | |
| document.addEventListener('click', handleCTAClick); | |
| document.addEventListener('play', handleVideoPlay, true); | |
| document.addEventListener('copy', handleCopy); | |
| window.addEventListener('scroll', handleScroll, { passive: true }); | |
| // Watch for color mode changes | |
| const colorModeObserver = new MutationObserver(mutations => { | |
| mutations.forEach(mutation => { | |
| if (mutation.attributeName === 'data-theme') { | |
| trackEvent( | |
| 'User Preference', | |
| 'Color Mode Change', | |
| document.documentElement.getAttribute('data-theme'), | |
| ); | |
| } | |
| }); | |
| }); | |
| colorModeObserver.observe(document.documentElement, { attributes: true }); | |
| // Set up Algolia tracking | |
| const algoliaObserver = setupAlgoliaTracking(); | |
| // Initial page tracking | |
| handleRouteChange(); | |
| // Cleanup | |
| return () => { | |
| routeHandlers.forEach(({ eventName, handler }) => { | |
| document.removeEventListener(eventName, handler); | |
| }); | |
| if (originalPushState) { | |
| window.history.pushState = originalPushState; | |
| window.removeEventListener('popstate', handleRouteChange); | |
| } | |
| document.removeEventListener('click', handleLinkClick); | |
| document.removeEventListener('click', handleCTAClick); | |
| document.removeEventListener('play', handleVideoPlay, true); | |
| document.removeEventListener('copy', handleCopy); | |
| window.removeEventListener('scroll', handleScroll); | |
| if (algoliaObserver) { | |
| algoliaObserver.disconnect(); | |
| } | |
| if (colorModeObserver) { | |
| colorModeObserver.disconnect(); | |
| } | |
| }; | |
| } | |
| }, []); | |
| return children; | |
| } | |