-
Notifications
You must be signed in to change notification settings - Fork 15.1k
Expand file tree
/
Copy pathexplain-code.ts
More file actions
100 lines (87 loc) · 2.77 KB
/
Copy pathexplain-code.ts
File metadata and controls
100 lines (87 loc) · 2.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import "../components/explain-code-sheet/explain-code-sheet";
import tippy, { type Instance } from "tippy.js";
function getCodeBlockPosition(button: HTMLElement): number {
const wrapperSelector = ".explain";
const codeSelector = "pre code";
const codeBlocks = document.querySelectorAll(codeSelector);
const wrapper = button.closest(wrapperSelector);
let currentBlock = wrapper?.previousElementSibling;
while (currentBlock) {
if (currentBlock.tagName === "PRE") {
currentBlock = currentBlock.querySelector(codeSelector);
break;
}
currentBlock = currentBlock.previousElementSibling;
}
if (!currentBlock) return 1;
return Array.from(codeBlocks).indexOf(currentBlock) + 1;
}
function handleExplainButtonClick(this: HTMLButtonElement, e: MouseEvent) {
e.preventDefault();
const position = getCodeBlockPosition(this);
const sheet = document.createElement("cfdocs-explain-code");
sheet.setAttribute("code-block-position", String(position));
document.body.appendChild(sheet);
}
const tippyInstances: Instance[] = [];
const copyClickListeners: Array<{
button: HTMLButtonElement;
listener: () => void;
}> = [];
let initialized = false;
function init() {
if (initialized) return;
initialized = true;
const explainButtons = document.querySelectorAll<HTMLButtonElement>(
"button[data-explain-code]",
);
explainButtons.forEach((button) => {
button.addEventListener("click", handleExplainButtonClick);
const instance = tippy(button, {
content: "Explain Code",
appendTo: () => document.body,
});
tippyInstances.push(instance);
});
const copyButtons = document.querySelectorAll<HTMLButtonElement>(
".expressive-code .copy > button",
);
copyButtons.forEach((button) => {
const instance = tippy(button, {
content: "Copy to clipboard",
appendTo: () => document.body,
});
tippyInstances.push(instance);
const listener = () => {
instance.setContent("Copied!");
instance.show();
setTimeout(() => {
instance.setContent("Copy to clipboard");
}, 2500);
};
button.addEventListener("click", listener);
copyClickListeners.push({ button, listener });
});
}
function cleanup() {
const explainButtons = document.querySelectorAll<HTMLButtonElement>(
"button[data-explain-code]",
);
explainButtons.forEach((button) => {
button.removeEventListener("click", handleExplainButtonClick);
});
tippyInstances.forEach((instance) => instance.destroy());
tippyInstances.length = 0;
copyClickListeners.forEach(({ button, listener }) =>
button.removeEventListener("click", listener),
);
copyClickListeners.length = 0;
initialized = false;
}
document.addEventListener("astro:before-swap", cleanup);
document.addEventListener("astro:page-load", init);
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init);
} else {
init();
}