d5575b58e3
Features: - Mission Control dashboard - HP Submissions tracking - AI Agents integration - Lead management CRM - Marketing email templates - Chrome extension support Tech: Next.js, TypeScript, Tailwind CSS, MySQL
191 lines
5.3 KiB
JavaScript
191 lines
5.3 KiB
JavaScript
// Content Script - runs on X.com
|
|
// Adds "Save to Hookd" option to tweet/post menu
|
|
|
|
console.log('Hookd content script loaded');
|
|
|
|
// Listen for messages from background
|
|
chrome.runtime.onMessage.addListener((msg, sender, response) => {
|
|
if (msg.type === 'GET_SAVED') {
|
|
response([]);
|
|
}
|
|
});
|
|
|
|
// Add "Save to Hookd" to X's menu
|
|
function addHookdOption() {
|
|
// Find all "more" buttons (the ... button on tweets/posts)
|
|
document.querySelectorAll('[data-testid="tweet"] [role="button"], [data-testid="tweet"] [aria-label*="more"], [data-testid="tweet"] [aria-label*="More"]').forEach(menuBtn => {
|
|
// Check if we already added our option
|
|
if (menuBtn.closest('[data-testid="tweet"]')?.querySelector('.hookd-menu-option')) continue;
|
|
|
|
const tweet = menuBtn.closest('[data-testid="tweet"]');
|
|
if (!tweet) return;
|
|
|
|
// Create save button
|
|
const saveBtn = document.createElement('div');
|
|
saveBtn.className = 'hookd-menu-option';
|
|
saveBtn.style.cssText = `
|
|
padding: 12px 16px;
|
|
cursor: pointer;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
font-size: 15px;
|
|
color: #fff;
|
|
`;
|
|
saveBtn.innerHTML = '<span style="font-size:18px;">📌</span><span>Save to Hookd</span>';
|
|
|
|
saveBtn.addEventListener('click', (e) => {
|
|
e.stopPropagation();
|
|
saveTweet(tweet);
|
|
});
|
|
|
|
// Find the dropdown menu and append
|
|
const dropdown = menuBtn.closest('[role="menu"]') || menuBtn.closest('div[aria-labelledby]');
|
|
if (dropdown && !dropdown.querySelector('.hookd-menu-option')) {
|
|
dropdown.appendChild(saveBtn);
|
|
}
|
|
});
|
|
|
|
// Also try to find DM more options
|
|
document.querySelectorAll('[data-testid="DMMessage"] [role="button"]').forEach(btn => {
|
|
if (btn.textContent.includes('more') || btn.getAttribute('aria-label')?.includes('more')) {
|
|
const dm = btn.closest('[data-testid="DMMessage"]');
|
|
if (dm && !dm.querySelector('.hookd-menu-option')) {
|
|
const saveBtn = document.createElement('div');
|
|
saveBtn.className = 'hookd-menu-option';
|
|
saveBtn.style.cssText = `
|
|
padding: 8px 12px;
|
|
cursor: pointer;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
font-size: 13px;
|
|
`;
|
|
saveBtn.innerHTML = '📌 Save to Hookd';
|
|
|
|
saveBtn.addEventListener('click', (e) => {
|
|
e.stopPropagation();
|
|
saveDM(dm);
|
|
});
|
|
|
|
// Insert after the clickable area
|
|
btn.parentElement?.appendChild(saveBtn);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// Save tweet
|
|
function saveTweet(tweetElement) {
|
|
try {
|
|
// Extract author
|
|
const authorEl = tweetElement.querySelector('[data-testid="User-Name"] span a[role="link"]') ||
|
|
tweetElement.querySelector('a[tabindex="-1"]');
|
|
const author = authorEl?.textContent?.trim()?.replace('@', '') || 'unknown';
|
|
|
|
// Extract content
|
|
const contentEl = tweetElement.querySelector('[data-testid="tweetText"]');
|
|
const content = contentEl?.textContent?.trim() || '';
|
|
|
|
// Extract link
|
|
const linkEl = tweetElement.querySelector('a[href*="/status/"]');
|
|
const link = linkEl?.href || '';
|
|
|
|
const item = {
|
|
id: Date.now(),
|
|
author: author,
|
|
content: content.substring(0, 500),
|
|
link: link,
|
|
source: 'tweet',
|
|
time: new Date().toISOString()
|
|
};
|
|
|
|
// Save to storage via background
|
|
chrome.runtime.sendMessage({
|
|
type: 'SAVE_ITEM',
|
|
data: item
|
|
}, (response) => {
|
|
if (response?.success) {
|
|
showNotification('Saved to Hookd!');
|
|
} else {
|
|
showNotification('Failed to save');
|
|
}
|
|
});
|
|
} catch (err) {
|
|
console.error('Hookd save error:', err);
|
|
showNotification('Error saving');
|
|
}
|
|
}
|
|
|
|
// Save DM
|
|
function saveDM(dmElement) {
|
|
try {
|
|
const contentEl = dmElement.querySelector('[data-testid="dmMessageContent"]');
|
|
const content = contentEl?.textContent?.trim() || '';
|
|
|
|
const item = {
|
|
id: Date.now(),
|
|
author: 'DM',
|
|
content: content.substring(0, 500),
|
|
source: 'dm',
|
|
time: new Date().toISOString()
|
|
};
|
|
|
|
chrome.runtime.sendMessage({
|
|
type: 'SAVE_ITEM',
|
|
data: item
|
|
}, (response) => {
|
|
if (response?.success) {
|
|
showNotification('Saved to Hookd!');
|
|
} else {
|
|
showNotification('Failed to save');
|
|
}
|
|
});
|
|
} catch (err) {
|
|
console.error('Hookd save error:', err);
|
|
}
|
|
}
|
|
|
|
// Show notification
|
|
function showNotification(message) {
|
|
const notif = document.createElement('div');
|
|
notif.style.cssText = `
|
|
position: fixed;
|
|
bottom: 20px;
|
|
right: 20px;
|
|
background: #4F46E5;
|
|
color: white;
|
|
padding: 12px 20px;
|
|
border-radius: 8px;
|
|
font-family: Arial, sans-serif;
|
|
font-size: 14px;
|
|
z-index: 99999;
|
|
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
|
|
`;
|
|
notif.textContent = message;
|
|
document.body.appendChild(notif);
|
|
|
|
setTimeout(() => {
|
|
notif.style.opacity = '0';
|
|
notif.style.transition = 'opacity 0.3s';
|
|
setTimeout(() => notif.remove(), 300);
|
|
}, 2000);
|
|
}
|
|
|
|
// Watch for new elements
|
|
const observer = new MutationObserver(() => {
|
|
addHookdOption();
|
|
});
|
|
|
|
// Start observing
|
|
observer.observe(document.body, {
|
|
childList: true,
|
|
subtree: true
|
|
});
|
|
|
|
// Initial scan
|
|
setTimeout(addHookdOption, 1000);
|
|
setTimeout(addHookdOption, 3000);
|
|
|
|
console.log('Hookd content script initialized');
|