diff --git a/entrypoints/content.ts b/entrypoints/content.ts index 109cdfd..b656295 100644 --- a/entrypoints/content.ts +++ b/entrypoints/content.ts @@ -243,91 +243,99 @@ export default defineContentScript({ toolbar!.appendChild(btn); }); - // ── Separator ──────────────────────────────────────────────────────────── - const sep = document.createElement('div'); - Object.assign(sep.style, { - width: '1px', - height: '20px', - background: 'rgba(205,214,244,0.15)', - margin: '0 2px', - flexShrink: '0', + // ─── More button (Copy As + Download) ──────────────────────────────────── + const moreBtn = document.createElement('button'); + moreBtn.textContent = '⋯ More'; + moreBtn.setAttribute('data-lexai', 'true'); + Object.assign(moreBtn.style, { + background: 'rgba(49,50,68,0.8)', + color: '#a6adc8', + border: '1px solid rgba(205,214,244,0.15)', + borderRadius: '6px', + padding: '5px 10px', + fontSize: '12px', + fontWeight: '600', + cursor: 'pointer', + whiteSpace: 'nowrap', }); - toolbar!.appendChild(sep); - // ── LEXAI-19: Copy As button ───────────────────────────────────────────── - const copyAsBtn = document.createElement('button'); - copyAsBtn.textContent = '⎘ Copy As'; - copyAsBtn.setAttribute('data-lexai', 'true'); - Object.assign(copyAsBtn.style, { - background: 'rgba(49,50,68,0.8)', - color: '#f9e2af', - border: '1px solid rgba(205,214,244,0.1)', - borderRadius: '7px', - padding: '4px 10px', - fontSize: '12px', - fontWeight: '600', - cursor: 'pointer', - transition: 'all 0.15s ease', - letterSpacing: '0.01em', - whiteSpace: 'nowrap', - }); - copyAsBtn.addEventListener('mouseenter', () => { - copyAsBtn.style.background = 'rgba(69,71,90,0.9)'; - copyAsBtn.style.borderColor = '#f9e2af50'; - copyAsBtn.style.transform = 'translateY(-1px)'; - }); - copyAsBtn.addEventListener('mouseleave', () => { - copyAsBtn.style.background = 'rgba(49,50,68,0.8)'; - copyAsBtn.style.borderColor = 'rgba(205,214,244,0.1)'; - copyAsBtn.style.transform = 'translateY(0)'; - }); - copyAsBtn.addEventListener('mousedown', (e) => { - e.preventDefault(); - captureForButton(); - }); - copyAsBtn.addEventListener('click', (e) => { - e.stopPropagation(); - showCopyAsModal(selectedText); - }); - toolbar!.appendChild(copyAsBtn); + // Dropdown menu + let moreMenu: HTMLElement | null = null; - // ── LEXAI-20: Download button ──────────────────────────────────────────── - const downloadBtn = document.createElement('button'); - downloadBtn.textContent = '⬇ Save'; - downloadBtn.setAttribute('data-lexai', 'true'); - Object.assign(downloadBtn.style, { - background: 'rgba(49,50,68,0.8)', - color: '#9399b2', - border: '1px solid rgba(205,214,244,0.1)', - borderRadius: '7px', - padding: '4px 10px', - fontSize: '12px', - fontWeight: '600', - cursor: 'pointer', - transition: 'all 0.15s ease', - letterSpacing: '0.01em', - whiteSpace: 'nowrap', - }); - downloadBtn.addEventListener('mouseenter', () => { - downloadBtn.style.background = 'rgba(69,71,90,0.9)'; - downloadBtn.style.borderColor = '#9399b250'; - downloadBtn.style.transform = 'translateY(-1px)'; - }); - downloadBtn.addEventListener('mouseleave', () => { - downloadBtn.style.background = 'rgba(49,50,68,0.8)'; - downloadBtn.style.borderColor = 'rgba(205,214,244,0.1)'; - downloadBtn.style.transform = 'translateY(0)'; - }); - downloadBtn.addEventListener('mousedown', (e) => { - e.preventDefault(); - captureForButton(); - }); - downloadBtn.addEventListener('click', (e) => { + function closeMoveMenu() { + if (moreMenu) { moreMenu.remove(); moreMenu = null; } + } + + moreBtn.addEventListener('mousedown', (e) => e.preventDefault()); + moreBtn.addEventListener('click', (e) => { e.stopPropagation(); - hideToolbar(); - downloadAsText(selectedText); + if (moreMenu) { closeMoveMenu(); return; } + + moreMenu = document.createElement('div'); + moreMenu.setAttribute('data-lexai', 'true'); + Object.assign(moreMenu.style, { + position: 'fixed', + background: 'rgba(30,30,46,0.98)', + border: '1px solid rgba(205,214,244,0.15)', + borderRadius: '8px', + padding: '4px', + zIndex: '2147483647', + minWidth: '140px', + boxShadow: '0 4px 20px rgba(0,0,0,0.4)', + display: 'flex', + flexDirection: 'column', + gap: '2px', + }); + + // Position above the More button + const rect = moreBtn.getBoundingClientRect(); + moreMenu.style.left = rect.left + 'px'; + moreMenu.style.top = (rect.top - 8) + 'px'; + moreMenu.style.transform = 'translateY(-100%)'; + + const menuItems = [ + { label: '⎘ Copy As', action: 'copy-as' }, + { label: '⬇ Download', action: 'download' }, + ]; + + menuItems.forEach(({ label, action }) => { + const item = document.createElement('button'); + item.textContent = label; + item.setAttribute('data-lexai', 'true'); + Object.assign(item.style, { + background: 'transparent', + color: '#cdd6f4', + border: 'none', + borderRadius: '6px', + padding: '7px 12px', + fontSize: '13px', + cursor: 'pointer', + textAlign: 'left', + width: '100%', + }); + item.addEventListener('mouseenter', () => { item.style.background = 'rgba(137,180,250,0.1)'; }); + item.addEventListener('mouseleave', () => { item.style.background = 'transparent'; }); + item.addEventListener('mousedown', (e) => e.preventDefault()); + item.addEventListener('click', () => { + closeMoveMenu(); + captureForButton(); // ensure selection is captured + if (action === 'download') { + downloadAsText(selectedText); + } else { + showCopyAsModal(selectedText); + } + }); + moreMenu!.appendChild(item); + }); + + document.body.appendChild(moreMenu); }); - toolbar!.appendChild(downloadBtn); + + toolbar!.appendChild(moreBtn); + + // Close dropdown on outside click / scroll + document.addEventListener('click', closeMoveMenu); + document.addEventListener('scroll', closeMoveMenu, { passive: true }); document.body.appendChild(toolbar); }