diff --git a/README.md b/README.md index b52ba79..a9768dc 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,8 @@ 2. Наведите курсор — элемент подсвечивается, рядом метка с тегом. 3. **Клик** по элементу открывает форму — опишите правку, сохраните (`Ctrl+Enter` или кнопка). + **`Ctrl+Shift+Enter`** — быстрый промпт: сразу копирует правку в буфер, + не добавляя её в общий список. 4. **Shift+клик** по следующему элементу добавляет его к текущей правке (один текст → несколько элементов). 5. `Escape` — закрыть форму / выйти из режима. diff --git a/src/content.js b/src/content.js index aa8140b..ac87304 100644 --- a/src/content.js +++ b/src/content.js @@ -77,7 +77,14 @@ font-weight: 600; } button.save:hover { background: #4f46e5; } + button.quick:hover { background: #26334d; border-color: #475569; } button.cancel:hover { background: #26334d; } + .toast { + position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%); + background: #6366f1; color: #fff; padding: 6px 14px; + border-radius: 20px; font: 12px/1.4 system-ui, sans-serif; + pointer-events: none; display: none; white-space: nowrap; + }
@@ -90,9 +97,11 @@
+
+
`; (document.documentElement || document).appendChild(host); @@ -103,7 +112,9 @@ const targetsList = root.querySelector('.targets'); const textarea = root.querySelector('textarea'); const saveBtn = root.querySelector('.save'); + const quickBtn = root.querySelector('.quick'); const cancelBtn = root.querySelector('.cancel'); + const toastEl = root.querySelector('.toast'); // ---------- Сообщения ---------- chrome.runtime.onMessage.addListener((msg, _sender, sendResponse) => { @@ -278,6 +289,10 @@ e.stopPropagation(); saveComment(); }); + quickBtn.addEventListener('click', (e) => { + e.stopPropagation(); + quickCopy(); + }); cancelBtn.addEventListener('click', (e) => { e.stopPropagation(); closeForm(); @@ -286,7 +301,8 @@ textarea.addEventListener('keydown', (e) => { if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) { e.stopPropagation(); - saveComment(); + if (e.shiftKey) quickCopy(); + else saveComment(); } }); @@ -338,6 +354,66 @@ return location.href.split('#')[0]; } + // Быстрый промпт: сразу в буфер, без сохранения в общий список. + function quickCopy() { + const prompt = textarea.value.trim(); + if (!prompt || !selected.length) return; + const contexts = selected.map(elementContext); + closeForm(); + clearSelection(); + copyToClipboard(buildQuickText(prompt, contexts)) + .then(() => showToast('Copied ✓')) + .catch(() => showToast('Copy failed')); + } + + // Тот же формат, что у одного блока из «Copy all» в popup. + function buildQuickText(prompt, contexts) { + const lines = []; + contexts.forEach((el, j) => { + const label = contexts.length > 1 ? `Элемент ${j + 1}` : 'Элемент'; + lines.push(`${label}: ${formatElement(el)}`); + }); + lines.push(prompt); + return lines.join('\n') + '\n'; + } + + function formatElement(el) { + const parts = [`<${el.tag}`]; + if (el.cls) parts.push(` class="${el.cls}"`); + if (el.text) parts.push(` «${el.text}»`); + return `\`${el.selector}\` ${parts.join('')}>`; + } + + async function copyToClipboard(text) { + try { + await navigator.clipboard.writeText(text); + } catch { + fallbackCopy(text); + } + } + + function fallbackCopy(text) { + const ta = document.createElement('textarea'); + ta.value = text; + ta.style.cssText = 'position: fixed; opacity: 0; pointer-events: none;'; + root.appendChild(ta); + ta.focus(); + ta.select(); + document.execCommand('copy'); + ta.remove(); + } + + let toastTimer = null; + + function showToast(msg) { + toastEl.textContent = msg; + toastEl.style.display = 'block'; + clearTimeout(toastTimer); + toastTimer = setTimeout(() => { + toastEl.style.display = 'none'; + }, 1400); + } + function saveComment() { const prompt = textarea.value.trim(); if (!prompt || !selected.length) return;