From 5f7f9741097c9ccfb51985028186fbf120da8562 Mon Sep 17 00:00:00 2001 From: hemanth5055 Date: Sun, 3 Aug 2025 15:09:16 +0530 Subject: [PATCH] Added copy button to code translation panel --- frontend/scripts/ui.js | 182 ++++++++++++++++++++++++++--------------- 1 file changed, 118 insertions(+), 64 deletions(-) diff --git a/frontend/scripts/ui.js b/frontend/scripts/ui.js index e01a36c..86f787b 100644 --- a/frontend/scripts/ui.js +++ b/frontend/scripts/ui.js @@ -1,5 +1,9 @@ -export function injectOrUpdateTranslations(translations, originalElement, width) { - const componentStyles = ` +export function injectOrUpdateTranslations( + translations, + originalElement, + width +) { + const componentStyles = ` .tab-nav { display: flex; border-bottom: 1px solid #ccc; @@ -29,6 +33,31 @@ export function injectOrUpdateTranslations(translations, originalElement, width) .tab-content.active { display: block; } + .code-wrapper{ + position:relative + } + .copy-button { + position: absolute; + top: 8px; + right: 8px; + padding: 6px 12px; + font-size: 14px; + background-color: rgba(255, 255, 255, 0.08); /* soft overlay */ + border: 1px solid rgba(255, 255, 255, 0.2); + border-radius: 4px; + color: #f0f0f0; + cursor: pointer; + transition: background-color 0.3s, border-color 0.3s, color 0.3s; + z-index: 10; + } + .copy-button:hover { + background-color: rgba(255, 255, 255, 0.15); + border-color: rgba(255, 255, 255, 0.3); + color: #ffffff; + } + .copy-button:active { + background-color: rgba(255, 255, 255, 0.2); + } pre { margin: 0; white-space: pre-wrap; @@ -40,71 +69,96 @@ export function injectOrUpdateTranslations(translations, originalElement, width) } `; - let container = originalElement.nextElementSibling; + let container = originalElement.nextElementSibling; - if (!container || container.id !== 'my-code-translator-container') { - container = document.createElement('div'); - container.id = 'my-code-translator-container'; - const shadowRoot = container.attachShadow({ mode: 'open' }); - const prismTheme = document.createElement('link'); - prismTheme.rel = 'stylesheet'; - prismTheme.href = chrome.runtime.getURL('packages/prism.css'); - shadowRoot.appendChild(prismTheme); - const styleElement = document.createElement('style'); - styleElement.textContent = componentStyles; - shadowRoot.appendChild(styleElement); - const uiWrapper = document.createElement('div'); - uiWrapper.className = 'ui-wrapper'; - shadowRoot.appendChild(uiWrapper); - originalElement.parentNode.insertBefore(container, originalElement.nextSibling); - } + if (!container || container.id !== "my-code-translator-container") { + container = document.createElement("div"); + container.id = "my-code-translator-container"; + const shadowRoot = container.attachShadow({ mode: "open" }); + const prismTheme = document.createElement("link"); + prismTheme.rel = "stylesheet"; + prismTheme.href = chrome.runtime.getURL("packages/prism.css"); + shadowRoot.appendChild(prismTheme); + const styleElement = document.createElement("style"); + styleElement.textContent = componentStyles; + shadowRoot.appendChild(styleElement); + const uiWrapper = document.createElement("div"); + uiWrapper.className = "ui-wrapper"; + shadowRoot.appendChild(uiWrapper); + originalElement.parentNode.insertBefore( + container, + originalElement.nextSibling + ); + } - container.style.width = `${width}px`; - container.style.boxSizing = 'border-box'; - const shadowRoot = container.shadowRoot; - const uiWrapper = shadowRoot.querySelector('.ui-wrapper'); - uiWrapper.innerHTML = ''; - const tabNav = document.createElement('div'); - tabNav.className = 'tab-nav'; - const contentArea = document.createElement('div'); - contentArea.className = 'tab-content-area'; - uiWrapper.appendChild(tabNav); - uiWrapper.appendChild(contentArea); - Object.keys(translations).forEach(lang => { - const contentPanel = document.createElement('div'); - contentPanel.className = 'tab-content'; - contentPanel.dataset.lang = lang; - const langClass = `language-${lang.toLowerCase()}`; - const pre = document.createElement('pre'); - pre.className = langClass; - const code = document.createElement('code'); - code.className = langClass; - code.textContent = translations[lang]; - pre.appendChild(code); - contentPanel.appendChild(pre); - contentArea.appendChild(contentPanel); + container.style.width = `${width}px`; + container.style.boxSizing = "border-box"; + const shadowRoot = container.shadowRoot; + const uiWrapper = shadowRoot.querySelector(".ui-wrapper"); + uiWrapper.innerHTML = ""; + const tabNav = document.createElement("div"); + tabNav.className = "tab-nav"; + const contentArea = document.createElement("div"); + contentArea.className = "tab-content-area"; + uiWrapper.appendChild(tabNav); + uiWrapper.appendChild(contentArea); + Object.keys(translations).forEach((lang) => { + const contentPanel = document.createElement("div"); + contentPanel.className = "tab-content"; + contentPanel.dataset.lang = lang; + const codeWrapper = document.createElement("div"); + codeWrapper.className = "code-wrapper"; + const copyButton = document.createElement("div"); + copyButton.className = "copy-button"; + copyButton.innerText = "copy"; + copyButton.addEventListener("click", () => { + navigator.clipboard.writeText(translations[lang]).then(() => { + copyButton.innerText = "Copied!"; + setTimeout(() => (copyButton.innerText = "Copy"), 2000); + }); }); + const langClass = `language-${lang.toLowerCase()}`; + const pre = document.createElement("pre"); + pre.className = langClass; + const code = document.createElement("code"); + code.className = langClass; + code.textContent = translations[lang]; - Object.keys(translations).forEach((lang, index) => { - const tabButton = document.createElement('button'); - tabButton.className = 'tab-link'; - tabButton.textContent = lang; - tabButton.addEventListener('click', () => { - shadowRoot.querySelectorAll('.tab-link').forEach(btn => btn.classList.remove('active')); - shadowRoot.querySelectorAll('.tab-content').forEach(panel => panel.classList.remove('active')); - tabButton.classList.add('active'); - shadowRoot.querySelector(`.tab-content[data-lang="${lang}"]`).classList.add('active'); - }); - tabNav.appendChild(tabButton); - if (index === 0) { - tabButton.click(); - } + pre.appendChild(code); + codeWrapper.appendChild(copyButton); + codeWrapper.appendChild(pre); + contentPanel.appendChild(codeWrapper); + contentArea.appendChild(contentPanel); + }); + + Object.keys(translations).forEach((lang, index) => { + const tabButton = document.createElement("button"); + tabButton.className = "tab-link"; + tabButton.textContent = lang; + tabButton.addEventListener("click", () => { + shadowRoot + .querySelectorAll(".tab-link") + .forEach((btn) => btn.classList.remove("active")); + shadowRoot + .querySelectorAll(".tab-content") + .forEach((panel) => panel.classList.remove("active")); + tabButton.classList.add("active"); + shadowRoot + .querySelector(`.tab-content[data-lang="${lang}"]`) + .classList.add("active"); }); - try { - if (window.Prism) { - contentArea.querySelectorAll(`pre[class*="language-"]`).forEach(element => window.Prism.highlightElement(element)); - } - } catch (e) { - console.error('CodeTranslateAI: Error highlighting syntax.', e); + tabNav.appendChild(tabButton); + if (index === 0) { + tabButton.click(); + } + }); + try { + if (window.Prism) { + contentArea + .querySelectorAll(`pre[class*="language-"]`) + .forEach((element) => window.Prism.highlightElement(element)); } -} \ No newline at end of file + } catch (e) { + console.error("CodeTranslateAI: Error highlighting syntax.", e); + } +}