@@ -7,4 +7,88 @@ import AboutContent from '../content/pages/about.mdx';
77 <div class =" openai-prose mx-auto w-full max-w-[46rem] min-w-0" >
88 <AboutContent />
99 </div >
10+
11+ <script >
12+ (() => {
13+ const container = document.querySelector('.openai-prose');
14+ if (!container) return;
15+
16+ const headings = Array.from(container.querySelectorAll('h1, h2, h3, h4, h5, h6'));
17+ if (headings.length === 0) return;
18+
19+ const used = new Set();
20+ for (const h of headings) {
21+ if (h.id) used.add(h.id);
22+ }
23+
24+ const slugify = (s) => {
25+ return String(s || '')
26+ .toLowerCase()
27+ .trim()
28+ .replace(/['’]/g, '')
29+ .replace(/[^a-z0-9]+/g, '-')
30+ .replace(/^-+|-+$/g, '');
31+ };
32+
33+ const ensureId = (h) => {
34+ if (h.id) return h.id;
35+ const base = slugify(h.textContent);
36+ let id = base || 'section';
37+ let n = 2;
38+ while (used.has(id)) {
39+ id = `${base || 'section'}-${n}`;
40+ n += 1;
41+ }
42+ h.id = id;
43+ used.add(id);
44+ return id;
45+ };
46+
47+ const copyText = async (text) => {
48+ if (navigator.clipboard && window.isSecureContext) {
49+ await navigator.clipboard.writeText(text);
50+ return;
51+ }
52+ const ta = document.createElement('textarea');
53+ ta.value = text;
54+ ta.setAttribute('readonly', '');
55+ ta.style.position = 'fixed';
56+ ta.style.top = '-9999px';
57+ document.body.appendChild(ta);
58+ ta.select();
59+ document.execCommand('copy');
60+ document.body.removeChild(ta);
61+ };
62+
63+ const copyHeadingLink = async (h) => {
64+ const id = ensureId(h);
65+ const u = new URL(window.location.href);
66+ u.hash = id;
67+ await copyText(u.toString());
68+ window.history.replaceState(null, '', u.toString());
69+
70+ const prevTitle = h.getAttribute('title') || '';
71+ h.setAttribute('title', 'Copied link');
72+ window.setTimeout(() => {
73+ if (prevTitle) h.setAttribute('title', prevTitle);
74+ else h.removeAttribute('title');
75+ }, 1200);
76+ };
77+
78+ for (const h of headings) {
79+ ensureId(h);
80+ h.classList.add('cursor-pointer', 'select-none');
81+ h.setAttribute('role', 'button');
82+ h.tabIndex = 0;
83+ h.addEventListener('click', () => {
84+ copyHeadingLink(h).catch(() => {});
85+ });
86+ h.addEventListener('keydown', (e) => {
87+ if (e.key !== 'Enter' && e.key !== ' ') return;
88+ e.preventDefault();
89+ copyHeadingLink(h).catch(() => {});
90+ });
91+ }
92+ })();
93+ </script >
1094</BaseLayout >
0 commit comments