Skip to content

Commit b00fbb3

Browse files
committed
update theme to support download
1 parent 566e7de commit b00fbb3

1 file changed

Lines changed: 75 additions & 0 deletions

File tree

theme/layout/index.tsx

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,81 @@ export default () => {
5454
window.parent.postMessage(window.location.href, "*");
5555
}, []);
5656

57+
// Handle file download links
58+
useEffect(() => {
59+
const DOWNLOAD_EXTENSIONS = ['.ipynb', '.zip', '.tgz', '.tar.gz', '.sh', '.py', '.sql'];
60+
61+
const getPathname = (href: string): string => {
62+
try {
63+
return new URL(href, window.location.origin).pathname;
64+
} catch {
65+
return href.split('?')[0].split('#')[0];
66+
}
67+
};
68+
69+
const shouldDownload = (pathname: string): boolean => {
70+
const lowerPath = pathname.toLowerCase();
71+
return DOWNLOAD_EXTENSIONS.some(ext => lowerPath.endsWith(ext));
72+
};
73+
74+
const downloadFile = (url: string, filename: string) => {
75+
const isSameOrigin = url.startsWith('/') || url.startsWith(window.location.origin);
76+
77+
if (isSameOrigin) {
78+
fetch(url)
79+
.then(res => res.ok ? res.blob() : Promise.reject(new Error('Failed to fetch')))
80+
.then(blob => {
81+
const blobUrl = window.URL.createObjectURL(blob);
82+
const a = document.createElement('a');
83+
a.href = blobUrl;
84+
a.download = filename;
85+
a.style.display = 'none';
86+
document.body.appendChild(a);
87+
a.click();
88+
setTimeout(() => {
89+
window.URL.revokeObjectURL(blobUrl);
90+
document.body.removeChild(a);
91+
}, 100);
92+
})
93+
.catch(() => console.warn('Failed to download file:', url));
94+
} else {
95+
const a = document.createElement('a');
96+
a.href = url;
97+
a.download = filename;
98+
a.style.display = 'none';
99+
document.body.appendChild(a);
100+
a.click();
101+
setTimeout(() => document.body.removeChild(a), 100);
102+
}
103+
};
104+
105+
const handleDownloadLinks = () => {
106+
document.querySelectorAll('a[href]:not([data-download-handled])').forEach((link) => {
107+
const href = link.getAttribute('href');
108+
if (!href) return;
109+
110+
const pathname = getPathname(href);
111+
if (!shouldDownload(pathname)) return;
112+
113+
link.setAttribute('data-download-handled', 'true');
114+
link.addEventListener('click', (e: Event) => {
115+
e.preventDefault();
116+
e.stopPropagation();
117+
e.stopImmediatePropagation();
118+
downloadFile(href, pathname.split('/').pop() || 'download');
119+
}, { capture: true });
120+
});
121+
};
122+
123+
handleDownloadLinks();
124+
const observer = new MutationObserver(() => setTimeout(handleDownloadLinks, 100));
125+
observer.observe(document.querySelector('.rspress-doc-content') || document.body, {
126+
childList: true,
127+
subtree: true
128+
});
129+
return () => observer.disconnect();
130+
}, []);
131+
57132
return (
58133
<Layout
59134
uiSwitch={uiSwitch}

0 commit comments

Comments
 (0)