2024-10-26 15:01:33 -04:00
|
|
|
// assets/js/hooks/code_block_hook.js
|
|
|
|
|
import { codeToHtml } from "shiki";
|
|
|
|
|
|
|
|
|
|
const CodeBlockHook = {
|
|
|
|
|
mounted() {
|
|
|
|
|
const code = this.el.dataset.code;
|
|
|
|
|
const language = this.el.dataset.language;
|
|
|
|
|
const highlightedLines = JSON.parse(
|
|
|
|
|
this.el.dataset.highlightedLines || "[]",
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const lines = code.split("\n");
|
|
|
|
|
|
2024-10-26 21:41:22 -04:00
|
|
|
console.log(lines.length, lines);
|
|
|
|
|
|
2024-10-26 15:01:33 -04:00
|
|
|
// Convert line numbers to decorations
|
|
|
|
|
const decorations = highlightedLines
|
|
|
|
|
.map((line) => {
|
|
|
|
|
// Convert to 0-based index and ensure valid line number
|
|
|
|
|
const lineIndex = line - 1;
|
|
|
|
|
if (lineIndex < 0 || lineIndex >= lines.length) return null;
|
|
|
|
|
|
|
|
|
|
// Get the actual line length
|
|
|
|
|
const lineLength = lines[lineIndex].length;
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
// Line numbers are 0-indexed
|
|
|
|
|
start: { line: lineIndex, character: 0 },
|
|
|
|
|
end: { line: lineIndex, character: lineLength },
|
|
|
|
|
properties: {
|
|
|
|
|
// Apply both background color and a class for flexibility
|
|
|
|
|
class: "highlight",
|
|
|
|
|
style: "background-color: rgba(200,200,255,0.1);",
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
})
|
|
|
|
|
.filter(Boolean); // Remove any null entries from invalid line numbers
|
|
|
|
|
|
|
|
|
|
codeToHtml(code, {
|
|
|
|
|
lang: language,
|
|
|
|
|
theme: "catppuccin-mocha",
|
2024-10-26 21:41:22 -04:00
|
|
|
transformers: [
|
|
|
|
|
{
|
|
|
|
|
line(node, line) {
|
|
|
|
|
node.properties["data-line"] = line;
|
|
|
|
|
if (highlightedLines.includes(line)) {
|
|
|
|
|
this.addClassToHast(node, "highlighted");
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
],
|
2024-10-26 15:01:33 -04:00
|
|
|
}).then((html) => {
|
|
|
|
|
console.log(html);
|
|
|
|
|
|
|
|
|
|
// Replace the code content while preserving the pre/code structure
|
|
|
|
|
const tempDiv = document.createElement("div");
|
|
|
|
|
tempDiv.innerHTML = html;
|
|
|
|
|
const codeContent = tempDiv.querySelector("code");
|
|
|
|
|
|
|
|
|
|
if (codeContent) {
|
|
|
|
|
this.el.querySelector("code").innerHTML = codeContent.innerHTML;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default CodeBlockHook;
|