create gists

This commit is contained in:
zack 2024-10-26 15:01:33 -04:00
parent 79a17290d5
commit 43a8412f06
No known key found for this signature in database
GPG key ID: 5F873416BCF59F35
90 changed files with 1777 additions and 2107 deletions

View file

@ -21,6 +21,55 @@ import "phoenix_html";
import { Socket } from "phoenix";
import { LiveSocket } from "phoenix_live_view";
import topbar from "../vendor/topbar";
import CodeBlockHook from "./hooks/code_block_hook";
import {
DropdownAnimation,
SearchableDropdown,
} from "./hooks/searchable_dropdown";
let Hooks = {
CodeBlockHook,
SearchableDropdown,
DropdownAnimation,
};
Hooks.ClickOutside = {
mounted() {
this.handleClick = (e) => {
if (!this.el.contains(e.target)) {
this.pushEventTo(this.el, "close_dropdown", {});
}
};
document.addEventListener("click", this.handleClick);
},
destroyed() {
document.removeEventListener("click", this.handleClick);
},
};
Hooks.ClientSearch = {
mounted() {
this.options = JSON.parse(this.el.dataset.options);
this.searchInput = this.el.querySelector("input");
this.optionsContainer = this.el.querySelector(
"#dropdown-options-container",
);
this.searchInput.addEventListener("input", (e) => {
const query = e.target.value.toLowerCase();
const options = this.el.querySelectorAll(".dropdown-option");
options.forEach((option) => {
const value = option.dataset.value.toLowerCase();
if (value.includes(query)) {
option.style.display = "";
} else {
option.style.display = "none";
}
});
});
},
};
window.addEventListener("phx:copy", (event) => {
let button = event.detail.dispatcher;
@ -40,6 +89,7 @@ let csrfToken = document
let liveSocket = new LiveSocket("/live", Socket, {
longPollFallbackMs: 2500,
params: { _csrf_token: csrfToken },
hooks: Hooks,
});
// Show progress bar on live navigation and form submits

View file

@ -0,0 +1,59 @@
// 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 || "[]",
);
console.log(code);
console.log("language", language);
const lines = code.split("\n");
// 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",
decorations,
}).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;

View file

@ -0,0 +1,32 @@
SearchableDropdown = {
mounted() {
this.el.addEventListener("input", (e) => {
const query = e.target.value.toLowerCase();
const dropdownId = this.el.dataset.dropdownId;
const optionsContainer = document.querySelector(`#${dropdownId}-options`);
const options = optionsContainer.querySelectorAll("li button");
options.forEach((option) => {
const text = option.textContent.toLowerCase();
option.parentElement.style.display = text.includes(query)
? "block"
: "none";
});
});
},
};
const DropdownAnimation = {
mounted() {
this.el.addEventListener("transitionend", (e) => {
if (
e.propertyName === "opacity" &&
this.el.classList.contains("fade-out")
) {
this.el.classList.add("hidden");
}
});
},
};
export { SearchableDropdown, DropdownAnimation };