This commit is contained in:
NAME
2026-05-15 10:02:53 +00:00
parent 65768643e0
commit a00f220940
6 changed files with 316 additions and 5 deletions
+210
View File
@@ -0,0 +1,210 @@
(() => {
'use strict';
let selectedTweetText = '';
// ===== A. LẮNG NGHE CHUỘT PHẢI ĐỂ LẤY TWEET TEXT =====
document.addEventListener('contextmenu', (e) => {
const article = e.target.closest('article[data-testid="tweet"]');
if (!article) {
selectedTweetText = '';
return;
}
const textContainer = article.querySelector('[data-testid="tweetText"]');
selectedTweetText = textContainer ? textContainer.innerText.trim() : '';
});
// ===== B. LẮNG NGHE MESSAGE TỪ BACKGROUND =====
chrome.runtime.onMessage.addListener((req, sender, sendResponse) => {
if (req.action === 'OPEN_FORM') {
if (!selectedTweetText) {
alert('Không tìm thấy nội dung tweet. Hãy chuột phải vào vùng văn bản của tweet.');
return;
}
openModal(selectedTweetText);
} else if (req.action === 'SHOW_RESULT') {
showResult(req.comment);
} else if (req.action === 'SHOW_ERROR') {
showError(req.error);
}
});
// ===== C. MỞ MODAL (DÙNG SHADOW DOM ĐỂ TRÁNH CSS XUNG ĐỘT) =====
function openModal(tweetText) {
removeModal(); // Xóa cũ nếu có
const host = document.createElement('div');
host.id = 'x-comment-ai-host';
Object.assign(host.style, {
position: 'fixed',
top: '0',
left: '0',
width: '100%',
height: '100%',
zIndex: '999999',
pointerEvents: 'none'
});
document.body.appendChild(host);
const shadow = host.attachShadow({ mode: 'open' });
const style = document.createElement('style');
style.textContent = `
.overlay {
position: fixed; inset: 0;
background: rgba(0,0,0,0.55);
display: flex; align-items: center; justify-content: center;
pointer-events: auto;
}
.modal {
background: #fff; color: #0f1419;
width: 420px; max-width: 92vw;
border-radius: 16px; padding: 24px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
box-shadow: 0 25px 50px rgba(0,0,0,0.25);
display: flex; flex-direction: column; gap: 14px;
animation: popIn 0.2s ease-out;
}
@keyframes popIn { from {opacity:0; transform:scale(0.96)} to {opacity:1; transform:scale(1)} }
h3 { margin: 0; font-size: 20px; }
.tweet-box {
background: #f7f9f9; border: 1px solid #cfd9de; border-radius: 10px;
padding: 12px; font-size: 14px; line-height: 1.4;
max-height: 120px; overflow-y: auto; color: #333;
}
label { font-size: 13px; font-weight: 700; color: #536471; }
select, button {
width: 100%; padding: 10px 12px; border-radius: 8px;
border: 1px solid #cfd9de; font-size: 14px; outline: none;
}
button.primary {
background: #1d9bf0; color: #fff; border: none;
font-weight: 700; cursor: pointer; margin-top: 4px;
}
button.primary:hover { background: #1a8cd8; }
button.primary:disabled { background: #8ecdf7; cursor: default; }
button.ghost {
background: transparent; color: #536471; border: 1px solid #cfd9de; margin-top: 6px;
}
.status {
display: none; padding: 12px; border-radius: 10px; font-size: 14px; line-height: 1.5; white-space: pre-wrap;
}
.status.ok { background: #e8f6fe; border: 1px solid #b4dffc; color: #0f1419; }
.status.err { background: #ffeaea; border: 1px solid #ffc5c5; color: #b00; }
.copy-hint { font-size: 12px; color: #536471; margin-top: 6px; text-align: center; }
`;
const overlay = document.createElement('div');
overlay.className = 'overlay';
overlay.addEventListener('click', (e) => {
if (e.target === overlay) removeModal();
});
const modal = document.createElement('div');
modal.className = 'modal';
modal.innerHTML = `
<h3>✍️ Viết Comment AI</h3>
<div>
<label>Nội dung Tweet</label>
<div class="tweet-box" id="ai-tweet"></div>
</div>
<div>
<label>Ngôn ngữ (Language)</label>
<select id="ai-language">
<option value="en">Anh</option>
<option value="ja">Nhật</option>
<option value="vi">Việt</option>
</select>
</div>
<div>
<label>Tone (Giọng điệu)</label>
<select id="ai-tone">
<option value="funny">😂 Hài hước</option>
<option value="professional">💼 Chuyên nghiệp</option>
<option value="friendly">😊 Thân thiện</option>
<option value="sarcastic">🌶️ Châm biếm</option>
<option value="neutral">😐 Trung lập</option>
<option value="excited">🤩 Hào hứng</option>
</select>
</div>
<div>
<label>Angle (Góc tiếp cận)</label>
<select id="ai-angle">
<option value="agree">👍 Đồng tình</option>
<option value="disagree">👎 Phản biện</option>
<option value="question">❓ Đặt câu hỏi</option>
<option value="add_info"> Bổ sung thông tin</option>
<option value="joke">🃏 Câu đùa / Meme</option>
</select>
</div>
<button class="primary" id="ai-run">🚀 Tạo Comment</button>
<div class="status" id="ai-status"></div>
<div class="copy-hint" id="ai-hint" style="display:none;">📋 Copy kết quả và tự dán vào ô comment nhé!</div>
<button class="ghost" id="ai-close">Đóng</button>
`;
overlay.appendChild(modal);
shadow.appendChild(style);
shadow.appendChild(overlay);
// Điền text tweet
shadow.getElementById('ai-tweet').textContent = tweetText;
// Events
shadow.getElementById('ai-close').addEventListener('click', removeModal);
shadow.getElementById('ai-run').addEventListener('click', () => {
const language = shadow.getElementById('ai-language').value;
const tone = shadow.getElementById('ai-tone').value;
const angle = shadow.getElementById('ai-angle').value;
const status = shadow.getElementById('ai-status');
const btn = shadow.getElementById('ai-run');
btn.disabled = true;
status.style.display = 'block';
status.className = 'status ok';
status.innerHTML = '<em>⏳ Đang tạo comment...</em>';
chrome.runtime.sendMessage({
action: 'GENERATE_COMMENT',
data: { text: tweetText, tone, angle, language }
});
});
}
// ===== D. HIỂN THỊ KẾT QUẢ / LỖI =====
function showResult(comment) {
const host = document.getElementById('x-comment-ai-host');
if (!host) return;
const s = host.shadowRoot;
const status = s.getElementById('ai-status');
const btn = s.getElementById('ai-run');
const hint = s.getElementById('ai-hint');
status.style.display = 'block';
status.className = 'status ok';
status.textContent = comment;
hint.style.display = 'block';
if (btn) btn.disabled = false;
}
function showError(msg) {
const host = document.getElementById('x-comment-ai-host');
if (!host) return;
const s = host.shadowRoot;
const status = s.getElementById('ai-status');
const btn = s.getElementById('ai-run');
status.style.display = 'block';
status.className = 'status err';
status.textContent = 'Lỗi: ' + msg;
if (btn) btn.disabled = false;
}
function removeModal() {
const el = document.getElementById('x-comment-ai-host');
if (el) el.remove();
}
})();