Skip to content

Commit 846a1d5

Browse files
committed
feat: adds color feature and bit bug fix
1 parent 710fd91 commit 846a1d5

2 files changed

Lines changed: 79 additions & 84 deletions

File tree

frontend/content.js

Lines changed: 77 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
55
if (message.type === "ENABLE_PICKER") {
66
if (!isPickerEnabled) enablePicker();
77
}
8+
return true;
89
});
910

1011
function enablePicker() {
@@ -37,157 +38,160 @@ function onMouseOut(e) {
3738
async function onClick(e) {
3839
e.preventDefault();
3940
e.stopPropagation();
40-
4141
const clickedElement = e.target;
42-
const selectedCode = clickedElement.textContent;
42+
const selectedCode = clickedElement.textContent.trim();
43+
if (!selectedCode) {
44+
disablePicker();
45+
return;
46+
}
4347
const cacheKey = `translation_${hashCode(selectedCode)}`;
4448
const originalWidth = clickedElement.getBoundingClientRect().width;
4549
disablePicker();
46-
4750
const { targetLanguage } = await chrome.storage.sync.get('targetLanguage');
4851
const lang = targetLanguage || 'Java';
49-
5052
const cachedData = await getFromCache(cacheKey);
5153
if (cachedData && cachedData[lang]) {
5254
injectOrUpdateTranslations(cachedData, clickedElement, originalWidth);
5355
return;
5456
}
55-
5657
const loadingDiv = document.createElement('div');
5758
loadingDiv.className = 'translator-loading';
5859
loadingDiv.textContent = `Translating to ${lang}...`;
60+
loadingDiv.style.width = `${originalWidth}px`;
5961
clickedElement.parentNode.insertBefore(loadingDiv, clickedElement.nextSibling);
60-
6162
chrome.runtime.sendMessage({ type: "TRANSLATE_CODE", code: selectedCode }, async (response) => {
6263
loadingDiv.remove();
63-
64+
if (chrome.runtime.lastError) {
65+
console.error('CodeTranslateAI: Message port closed unexpectedly.', chrome.runtime.lastError.message);
66+
alert('Error: Could not connect to the translation service.');
67+
return;
68+
}
6469
if (response.error) {
6570
alert(`Error: ${response.error}`);
6671
} else if (response.translation) {
6772
const cleanedTranslation = response.translation.replace(/```[a-z]*\n/g, '').replace(/```/g, '').trim();
68-
6973
const newData = cachedData || {};
7074
newData[lang] = cleanedTranslation;
7175
await saveToCache(cacheKey, newData, 10);
72-
7376
injectOrUpdateTranslations(newData, clickedElement, originalWidth);
7477
}
7578
});
7679
}
7780

7881
function injectOrUpdateTranslations(translations, originalElement, width) {
7982
const componentStyles = `
80-
.tab-nav {
81-
display: flex;
82-
border-bottom: 1px solid #ccc;
83-
background-color: #f0f0f0;
84-
}
85-
.tab-link {
86-
padding: 10px 15px;
87-
cursor: pointer;
88-
border: none;
89-
background-color: transparent;
90-
font-size: 1em;
91-
font-weight: 500;
92-
color: #333;
93-
border-bottom: 3px solid transparent;
83+
.tab-nav {
84+
display: flex;
85+
border-bottom: 1px solid #ccc;
86+
background-color: #f0f0f0;
9487
}
95-
.tab-link:hover {
96-
background-color: #e5e5e5;
88+
.tab-link {
89+
padding: 10px 15px;
90+
cursor: pointer;
91+
border: none;
92+
background-color: transparent;
93+
font-size: 1em;
94+
/* --- FIX 1: Make inactive tabs more visible --- */
95+
font-weight: 500;
96+
color: #555;
97+
border-bottom: 3px solid transparent;
9798
}
98-
.tab-link.active {
99-
color: #007bff;
100-
border-bottom: 3px solid #007bff;
99+
.tab-link:hover {
100+
background-color: #e5e5e5;
101101
}
102-
.tab-content-area {
103-
background-color: #fff;
102+
.tab-link.active {
103+
color: #007bff;
104+
font-weight: 600; /* Make active tab slightly bolder */
105+
border-bottom: 3px solid #007bff;
104106
}
105-
.tab-content {
106-
display: none;
107+
.tab-content {
108+
display: none;
107109
}
108-
.tab-content.active {
109-
display: block;
110+
.tab-content.active {
111+
display: block;
110112
}
111-
pre {
112-
margin: 0;
113-
padding: 16px;
114-
white-space: pre-wrap;
115-
word-wrap: break-word;
116-
background-color: #f6f8fa;
117-
border-top: 1px solid #ddd;
118-
margin-bottom: 10px;
113+
pre {
114+
margin: 0;
115+
white-space: pre-wrap;
116+
word-wrap: break-word;
119117
}
120-
code {
121-
font-family: monospace;
122-
font-size: 14px;
123-
color: #24292e;
124-
line-height: 1;
118+
code {
119+
font-family: monospace;
120+
/* --- FIX 2: Made the code font size smaller --- */
121+
font-size: 0.8em;
125122
}
126123
`;
127124

125+
// The rest of the function remains exactly the same...
128126
let container = originalElement.nextElementSibling;
129127
if (!container || container.id !== 'my-code-translator-container') {
130128
container = document.createElement('div');
131129
container.id = 'my-code-translator-container';
132-
133130
const shadowRoot = container.attachShadow({ mode: 'open' });
134131

132+
const prismTheme = document.createElement('link');
133+
prismTheme.rel = 'stylesheet';
134+
prismTheme.href = chrome.runtime.getURL('packages/prism.css');
135+
shadowRoot.appendChild(prismTheme);
136+
135137
const styleElement = document.createElement('style');
136138
styleElement.textContent = componentStyles;
137139
shadowRoot.appendChild(styleElement);
138140

139141
const uiWrapper = document.createElement('div');
142+
uiWrapper.className = 'ui-wrapper';
140143
shadowRoot.appendChild(uiWrapper);
141144

142145
originalElement.parentNode.insertBefore(container, originalElement.nextSibling);
143146
}
144147

145148
container.style.width = `${width}px`;
146149
container.style.boxSizing = 'border-box';
147-
148150
const shadowRoot = container.shadowRoot;
149-
const uiWrapper = shadowRoot.querySelector('div');
151+
const uiWrapper = shadowRoot.querySelector('.ui-wrapper');
150152
uiWrapper.innerHTML = '';
151-
152153
const tabNav = document.createElement('div');
153154
tabNav.className = 'tab-nav';
154-
155155
const contentArea = document.createElement('div');
156156
contentArea.className = 'tab-content-area';
157-
158157
uiWrapper.appendChild(tabNav);
159158
uiWrapper.appendChild(contentArea);
160-
161-
Object.keys(translations).forEach((lang, index) => {
162-
const tabButton = document.createElement('button');
163-
tabButton.className = 'tab-link';
164-
tabButton.textContent = lang;
165-
159+
Object.keys(translations).forEach(lang => {
166160
const contentPanel = document.createElement('div');
167161
contentPanel.className = 'tab-content';
168-
162+
contentPanel.dataset.lang = lang;
163+
const langClass = `language-${lang.toLowerCase()}`;
169164
const pre = document.createElement('pre');
165+
pre.className = langClass;
170166
const code = document.createElement('code');
167+
code.className = langClass;
171168
code.textContent = translations[lang];
172169
pre.appendChild(code);
173170
contentPanel.appendChild(pre);
174-
175-
tabNav.appendChild(tabButton);
176171
contentArea.appendChild(contentPanel);
177-
178-
if (index === 0) {
179-
tabButton.classList.add('active');
180-
contentPanel.classList.add('active');
181-
}
182-
172+
});
173+
Object.keys(translations).forEach((lang, index) => {
174+
const tabButton = document.createElement('button');
175+
tabButton.className = 'tab-link';
176+
tabButton.textContent = lang;
183177
tabButton.addEventListener('click', () => {
184178
shadowRoot.querySelectorAll('.tab-link').forEach(btn => btn.classList.remove('active'));
185179
shadowRoot.querySelectorAll('.tab-content').forEach(panel => panel.classList.remove('active'));
186-
187180
tabButton.classList.add('active');
188-
contentPanel.classList.add('active');
181+
shadowRoot.querySelector(`.tab-content[data-lang="${lang}"]`).classList.add('active');
189182
});
183+
tabNav.appendChild(tabButton);
184+
if (index === 0) {
185+
tabButton.click();
186+
}
190187
});
188+
try {
189+
if (window.Prism) {
190+
contentArea.querySelectorAll(`pre[class*="language-"]`).forEach(element => window.Prism.highlightElement(element));
191+
}
192+
} catch (e) {
193+
console.error('CodeTranslateAI: Error highlighting syntax.', e);
194+
}
191195
}
192196

193197
function hashCode(str) {
@@ -202,25 +206,16 @@ function hashCode(str) {
202206

203207
async function saveToCache(key, data, daysToExpire) {
204208
const expirationMs = daysToExpire * 24 * 60 * 60 * 1000;
205-
const cacheItem = {
206-
data: data,
207-
expiresAt: Date.now() + expirationMs,
208-
};
209+
const cacheItem = { data: data, expiresAt: Date.now() + expirationMs };
209210
await chrome.storage.local.set({ [key]: cacheItem });
210211
}
211212

212213
async function getFromCache(key) {
213214
const result = await chrome.storage.local.get(key);
214215
const cacheItem = result[key];
215-
216-
if (!cacheItem) {
217-
return null;
218-
}
219-
220-
if (Date.now() > cacheItem.expiresAt) {
221-
await chrome.storage.local.remove(key);
216+
if (!cacheItem || Date.now() > cacheItem.expiresAt) {
217+
if (cacheItem) await chrome.storage.local.remove(key);
222218
return null;
223219
}
224-
225220
return cacheItem.data;
226221
}

frontend/manifest.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
"content_scripts": [
2626
{
2727
"matches": ["<all_urls>"],
28-
"js": ["content.js"],
28+
"js": ["packages/prism.js", "content.js"],
2929
"css": ["styles.css"]
3030
}
3131
],
@@ -34,7 +34,7 @@
3434
},
3535
"web_accessible_resources": [
3636
{
37-
"resources": ["packages/prism/prism.js", "packages/prism/prism.css"],
37+
"resources": ["packages/prism.css"],
3838
"matches": ["<all_urls>"]
3939
}
4040
]

0 commit comments

Comments
 (0)