index.tsx
 1  import { MouseEvent, ReactNode, useCallback } from 'react';
 2  import { Version } from '@site/src/constants';
 3  
 4  interface NotebookDownloadButtonProps {
 5    children: ReactNode;
 6    href: string;
 7  }
 8  
 9  export function NotebookDownloadButton({ children, href }: NotebookDownloadButtonProps) {
10    const handleClick = useCallback(
11      async (e: MouseEvent) => {
12        e.preventDefault();
13  
14        if ((window as any).gtag) {
15          try {
16            (window as any).gtag('event', 'notebook-download', {
17              href,
18            });
19          } catch {
20            // do nothing if the gtag call fails
21          }
22        }
23  
24        if (!Version.includes('dev')) {
25          // Replace 'master' with the current version to pin the download to the released version
26          // and avoid 404 errors
27          href = href.replace(/\/master\//, `/v${Version}/`);
28        }
29  
30        const response = await fetch(href);
31        const blob = await response.blob();
32  
33        const url = window.URL.createObjectURL(blob);
34        const link = document.createElement('a');
35        link.style.display = 'none';
36        link.href = url;
37        const filename = href.split('/').pop();
38        link.download = filename;
39  
40        document.body.appendChild(link);
41        link.click();
42  
43        window.URL.revokeObjectURL(url);
44        document.body.removeChild(link);
45      },
46      [href],
47    );
48  
49    return (
50      <a
51        className="button button--primary"
52        style={{ marginBottom: '1rem', display: 'block', width: 'min-content' }}
53        href={href}
54        download
55        onClick={handleClick}
56      >
57        {children}
58      </a>
59    );
60  }