()
| 516 | * Setup modal functionality |
| 517 | */ |
| 518 | export function setupModal(): void { |
| 519 | const modal = document.getElementById("file-modal"); |
| 520 | |
| 521 | // Move modal to body level to escape ancestor stacking contexts |
| 522 | // This fixes the issue where modal appears below header/theme-toggle |
| 523 | if (modal && modal.parentElement !== document.body) { |
| 524 | document.body.appendChild(modal); |
| 525 | } |
| 526 | |
| 527 | const closeBtn = document.getElementById("close-modal"); |
| 528 | const copyBtn = document.getElementById("copy-btn"); |
| 529 | const installCommandBtn = document.getElementById("install-command-btn"); |
| 530 | const downloadBtn = document.getElementById("download-btn"); |
| 531 | const shareBtn = document.getElementById("share-btn"); |
| 532 | const renderBtn = document.getElementById("render-btn"); |
| 533 | const rawBtn = document.getElementById("raw-btn"); |
| 534 | const fileDropdown = document.getElementById("modal-file-dropdown"); |
| 535 | const fileButton = document.getElementById("modal-file-button"); |
| 536 | const fileToggle = document.getElementById("modal-file-toggle"); |
| 537 | const fileMenu = document.getElementById("modal-file-menu"); |
| 538 | |
| 539 | if (!modal) return; |
| 540 | |
| 541 | closeBtn?.addEventListener("click", () => closeModal()); |
| 542 | |
| 543 | modal.addEventListener("click", (e) => { |
| 544 | if (e.target === modal) closeModal(); |
| 545 | }); |
| 546 | |
| 547 | document.addEventListener("keydown", (e) => { |
| 548 | if (!modal.classList.contains("hidden")) { |
| 549 | if (e.key === "Escape") { |
| 550 | closeModal(); |
| 551 | } else { |
| 552 | handleModalKeydown(e, modal); |
| 553 | } |
| 554 | } |
| 555 | }); |
| 556 | |
| 557 | copyBtn?.addEventListener("click", async () => { |
| 558 | if (currentFileContent) { |
| 559 | const success = await copyToClipboard(currentFileContent); |
| 560 | showToast( |
| 561 | success ? "Copied to clipboard!" : "Failed to copy", |
| 562 | success ? "success" : "error" |
| 563 | ); |
| 564 | } |
| 565 | }); |
| 566 | |
| 567 | installCommandBtn?.addEventListener("click", async () => { |
| 568 | if (currentFilePath && currentFileType === "skill") { |
| 569 | const skill = await getSkillItemByFilePath(currentFilePath); |
| 570 | if (!skill) { |
| 571 | showToast("Could not resolve skill ID.", "error"); |
| 572 | return; |
| 573 | } |
| 574 | const command = `gh skills install ${REPO_IDENTIFIER} ${skill.id}`; |
| 575 | const originalContent = installCommandBtn.innerHTML; |
no test coverage detected