Skip to main content
Glama
Vivek-k3

Models PLUS

by Vivek-k3
index.ts6.95 kB
const modal = document.getElementById("modal") as HTMLDialogElement; const modalClose = document.getElementById("close")!; const help = document.getElementById("help")!; const search = document.getElementById("search")! as HTMLInputElement; ///////////////////////// // URL State Management ///////////////////////// function getQueryParams() { return new URLSearchParams(window.location.search); } function updateQueryParams(updates: Record<string, string | null>) { const params = getQueryParams(); for (const [key, value] of Object.entries(updates)) { if (value) { params.set(key, value); } else { params.delete(key); } } const newPath = params.toString() ? `${window.location.pathname}?${params.toString()}` : window.location.pathname; window.history.pushState({}, "", newPath); } function getColumnNameForURL(headerEl: Element): string { const text = headerEl.textContent?.trim().toLowerCase() || ""; return text.replace(/↑|↓/g, "").trim().split(/\s+/).slice(0, 2).join("-"); } function getColumnIndexByUrlName(name: string): number { const headers = document.querySelectorAll("th.sortable"); return Array.from(headers).findIndex( (header) => getColumnNameForURL(header) === name ); } ///////////////////////// // Handle "How to use" ///////////////////////// let y = 0; help.addEventListener("click", () => { y = window.scrollY; document.body.style.position = "fixed"; document.body.style.top = `-${y}px`; modal.showModal(); }); function closeDialog() { modal.close(); document.body.style.position = ""; document.body.style.top = ""; window.scrollTo(0, y); } modalClose.addEventListener("click", closeDialog); modal.addEventListener("cancel", closeDialog); modal.addEventListener("click", (e) => { if (e.target === modal) closeDialog(); }); //////////////////// // Handle Sorting //////////////////// let currentSort = { column: -1, direction: "asc" }; function sortTable(column: number, direction: "asc" | "desc") { const header = document.querySelectorAll("th.sortable")[column]; const columnType = header.getAttribute("data-type"); if (!columnType) return; // update state currentSort = { column, direction }; updateQueryParams({ sort: getColumnNameForURL(header), order: direction, }); // sort rows const tbody = document.querySelector("table tbody")!; const rows = Array.from( tbody.querySelectorAll("tr") ) as HTMLTableRowElement[]; rows.sort((a, b) => { const aValue = getCellValue(a.cells[column], columnType); const bValue = getCellValue(b.cells[column], columnType); // Handle undefined values - always sort to bottom if (aValue === undefined && bValue === undefined) return 0; if (aValue === undefined) return 1; if (bValue === undefined) return -1; let comparison = 0; if (columnType === "number" || columnType === "modalities") { comparison = (aValue as number) - (bValue as number); } else if (columnType === "boolean") { comparison = (aValue as string).localeCompare(bValue as string); } else { comparison = (aValue as string).localeCompare(bValue as string); } return direction === "asc" ? comparison : -comparison; }); rows.forEach((row) => tbody.appendChild(row)); // update sort indicators const headers = document.querySelectorAll("th.sortable"); headers.forEach((header, i) => { const indicator = header.querySelector(".sort-indicator")!; if (i === column) { indicator.textContent = direction === "asc" ? "↑" : "↓"; } else { indicator.textContent = ""; } }); } function getCellValue( cell: HTMLTableCellElement, type: string ): string | number | undefined { if (type === "modalities") return cell.querySelectorAll(".modality-icon").length; const text = cell.textContent?.trim() || ""; if (text === "-") return; if (type === "number") return parseFloat(text.replace(/[$,]/g, "")) || 0; return text; } document.querySelectorAll("th.sortable").forEach((header) => { header.addEventListener("click", () => { const column = Array.from(header.parentElement!.children).indexOf(header); const direction = currentSort.column === column && currentSort.direction === "asc" ? "desc" : "asc"; sortTable(column, direction); }); }); /////////////////// // Handle Search /////////////////// function filterTable(value: string) { const lowerCaseValues = value.toLowerCase().split(",").filter(str => str.trim() !== ""); const rows = document.querySelectorAll( "table tbody tr" ) as NodeListOf<HTMLTableRowElement>; rows.forEach((row) => { const cellTexts = Array.from(row.cells).map((cell) => cell.textContent!.toLowerCase() ); const isVisible = lowerCaseValues.length === 0 || lowerCaseValues.some((lowerCaseValue) => cellTexts.some((text) => text.includes(lowerCaseValue))); row.style.display = isVisible ? "" : "none"; }); updateQueryParams({ search: value || null }); } search.addEventListener("input", () => { filterTable(search.value); }); document.addEventListener("keydown", (e) => { if ((e.metaKey || e.ctrlKey) && e.key === "k") { e.preventDefault(); search.focus(); } }); search.addEventListener("keydown", (e) => { if (e.key === "Escape") { search.value = ""; search.dispatchEvent(new Event("input")); } }); /////////////////////////////////// // Handle Copy model ID function /////////////////////////////////// (window as any).copyModelId = async ( button: HTMLButtonElement, modelId: string ) => { try { if (navigator.clipboard) { await navigator.clipboard.writeText(modelId); // Switch to check icon const copyIcon = button.querySelector(".copy-icon") as HTMLElement; const checkIcon = button.querySelector(".check-icon") as HTMLElement; copyIcon.style.display = "none"; checkIcon.style.display = "block"; // Switch back after 1 second setTimeout(() => { copyIcon.style.display = "block"; checkIcon.style.display = "none"; }, 1000); } } catch (err) { console.error("Failed to copy text: ", err); } }; /////////////////////////////////// // Initialize State from URL /////////////////////////////////// function initializeFromURL() { const params = getQueryParams(); (() => { const searchQuery = params.get("search"); if (!searchQuery) return; search.value = searchQuery; filterTable(searchQuery); })(); (() => { const columnName = params.get("sort"); if (!columnName) return; const columnIndex = getColumnIndexByUrlName(columnName); if (columnIndex === -1) return; const direction = (params.get("order") as "asc" | "desc") || "asc"; sortTable(columnIndex, direction); })(); } document.addEventListener("DOMContentLoaded", initializeFromURL); window.addEventListener("popstate", initializeFromURL);

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Vivek-k3/modelsplus'

If you have feedback or need assistance with the MCP directory API, please join our Discord server