Skip to content

Instantly share code, notes, and snippets.

@Ramblurr
Last active April 11, 2025 13:24
Show Gist options
  • Save Ramblurr/74b3d6c7f25939bd97fc221bec339f44 to your computer and use it in GitHub Desktop.
Save Ramblurr/74b3d6c7f25939bd97fc221bec339f44 to your computer and use it in GitHub Desktop.
// a simple widget for positioning HTML popovers using a vendored floating ui (because I can't use css anchor positioning yet)
const { computePosition, flip } = window.FloatingUIDOM;
export function ActionMenuPopover(container) {
const trigger = container.querySelector("[popovertarget]");
const popover = container.querySelector("[popover]");
const update = () => {
computePosition(trigger, popover, {
placement: "bottom",
middleware: [flip()],
}).then(({ x, y }) => {
Object.assign(popover.style, {
left: `${x}px`,
top: `${y}px`,
});
});
};
popover.addEventListener("toggle", update);
}
// shows a lightweight progress bar at the top of the screen while d* requests are in flight
document.addEventListener("datastar-sse", function (evt) {
const { elId, type } = evt.detail;
if (elId === "long-lived-sse") return;
if (type === "started") {
NProgress.start();
} else if (type === "finished") {
NProgress.done();
setTimeout(() => NProgress.remove(), 1000);
} else if (type === "error") {
NProgress.done();
NProgress.remove();
} else if (type === "retries-failed") {
NProgress.done();
NProgress.remove();
}
});
// a little typeahead search widget that handles the back button (server side d* sends the history push)
export function TypeaheadSearch(inputId, containerId) {
const searchPhrase = document.getElementById(inputId);
const container = document.getElementById(containerId);
if (!searchPhrase) return;
if (!container) return;
searchPhrase.focus();
if (searchPhrase.hasAttribute("data-history-bound")) return;
searchPhrase.setAttribute("data-history-bound", "true");
window.addEventListener("popstate", (event) => {
// the current URL already reflects the desired state.
const currentUrl = new URL(window.location.href);
const searchPhraseValue = currentUrl.searchParams.get("phrase") || "";
searchPhrase.value = searchPhraseValue;
const sections = currentUrl.searchParams.get("sections") || 0;
const historyChangeEvent = new CustomEvent("historychange", {
detail: {
phrase: searchPhrase.value,
sections: sections,
},
});
searchPhrase.dispatchEvent(historyChangeEvent);
});
container.addEventListener("historychange", (e) => {
searchPhrase.focus();
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment