feat: LEXAI-23 move Copy As + Download into More dropdown on toolbar
Some checks failed
CI — Test & Build / Test & Build (push) Failing after 45s

This commit is contained in:
Forge
2026-03-06 15:30:48 +08:00
parent 1490e6641f
commit 2bc73d5fc9

View File

@@ -243,91 +243,99 @@ export default defineContentScript({
toolbar!.appendChild(btn); toolbar!.appendChild(btn);
}); });
// ── Separator ──────────────────────────────────────────────────────────── // ─── More button (Copy As + Download) ────────────────────────────────────
const sep = document.createElement('div'); const moreBtn = document.createElement('button');
Object.assign(sep.style, { moreBtn.textContent = '⋯ More';
width: '1px', moreBtn.setAttribute('data-lexai', 'true');
height: '20px', Object.assign(moreBtn.style, {
background: 'rgba(205,214,244,0.15)',
margin: '0 2px',
flexShrink: '0',
});
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)', background: 'rgba(49,50,68,0.8)',
color: '#f9e2af', color: '#a6adc8',
border: '1px solid rgba(205,214,244,0.1)', border: '1px solid rgba(205,214,244,0.15)',
borderRadius: '7px', borderRadius: '6px',
padding: '4px 10px', padding: '5px 10px',
fontSize: '12px', fontSize: '12px',
fontWeight: '600', fontWeight: '600',
cursor: 'pointer', cursor: 'pointer',
transition: 'all 0.15s ease',
letterSpacing: '0.01em',
whiteSpace: 'nowrap', 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);
// ── LEXAI-20: Download button ──────────────────────────────────────────── // Dropdown menu
const downloadBtn = document.createElement('button'); let moreMenu: HTMLElement | null = null;
downloadBtn.textContent = '⬇ Save';
downloadBtn.setAttribute('data-lexai', 'true'); function closeMoveMenu() {
Object.assign(downloadBtn.style, { if (moreMenu) { moreMenu.remove(); moreMenu = null; }
background: 'rgba(49,50,68,0.8)', }
color: '#9399b2',
border: '1px solid rgba(205,214,244,0.1)', moreBtn.addEventListener('mousedown', (e) => e.preventDefault());
borderRadius: '7px', moreBtn.addEventListener('click', (e) => {
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) => {
e.stopPropagation(); e.stopPropagation();
hideToolbar(); 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); downloadAsText(selectedText);
} else {
showCopyAsModal(selectedText);
}
}); });
toolbar!.appendChild(downloadBtn); moreMenu!.appendChild(item);
});
document.body.appendChild(moreMenu);
});
toolbar!.appendChild(moreBtn);
// Close dropdown on outside click / scroll
document.addEventListener('click', closeMoveMenu);
document.addEventListener('scroll', closeMoveMenu, { passive: true });
document.body.appendChild(toolbar); document.body.appendChild(toolbar);
} }