diff --git a/packages/web/src/index.css b/packages/web/src/index.css index 58a4a5c4..f68e8118 100644 --- a/packages/web/src/index.css +++ b/packages/web/src/index.css @@ -330,7 +330,7 @@ tbody { color: var(--color-text-secondary); } - .model-id-cell { + .id-cell { display: flex; align-items: center; justify-content: space-between; @@ -351,11 +351,11 @@ tbody { transition: opacity 0.2s ease, color 0.2s ease; } - .model-id-cell:hover .copy-button { + .id-cell:hover .copy-button { opacity: 1; } - .model-id-cell .copy-button svg { + .id-cell .copy-button svg { display: block; } @@ -372,6 +372,11 @@ tbody { color: var(--color-brand) !important; } + /* Visual failure state when copy is not possible */ + .copy-button.failed { + color: #e11 !important; + } + .modalities { display: flex; gap: 0.25rem; @@ -546,4 +551,4 @@ dialog { } } -} \ No newline at end of file +} diff --git a/packages/web/src/index.ts b/packages/web/src/index.ts index 81afb434..6aeb8076 100644 --- a/packages/web/src/index.ts +++ b/packages/web/src/index.ts @@ -183,15 +183,14 @@ search.addEventListener("keydown", (e) => { }); /////////////////////////////////// -// Handle Copy model ID function +// Handle Copy ID function /////////////////////////////////// -(window as any).copyModelId = async ( - button: HTMLButtonElement, - modelId: string -) => { +// Generic copy function for model or provider IDs +// Copy text helper for buttons. This is now used by delegation below +async function copyText(button: HTMLButtonElement, id: string) { try { if (navigator.clipboard) { - await navigator.clipboard.writeText(modelId); + await navigator.clipboard.writeText(id); // Switch to check icon const copyIcon = button.querySelector(".copy-icon") as HTMLElement; @@ -209,7 +208,28 @@ search.addEventListener("keydown", (e) => { } catch (err) { console.error("Failed to copy text: ", err); } -}; +} + +// Attach to window for compatibility with any existing calling sites. +(window as any).copyText = copyText; + +// Event delegation: catch clicks on copy buttons and handle them safely. +document.addEventListener("click", (e) => { + const target = e.target as Element | null; + if (!target) return; + + const button = target.closest("button.copy-button") as HTMLButtonElement | null; + if (!button) return; + + const id = button.dataset.copyId; + if (!id) return; + + // Prevent accidental form submits/navigation + e.preventDefault(); + copyText(button, id); +}); + +// NOTE: If you need to support older releases, update the calling sites accordingly. /////////////////////////////////// // Initialize State from URL diff --git a/packages/web/src/render.tsx b/packages/web/src/render.tsx index a1bdfcc2..e810bcde 100644 --- a/packages/web/src/render.tsx +++ b/packages/web/src/render.tsx @@ -68,6 +68,59 @@ function renderProviderLogo(providerId: string) { return ; } +// Render a reusable table cell for IDs (provider/model). +function renderIdCell( + id: string, + label: string, + className = "id-cell" +) { + const textClass = "id-text"; + return ( +