"${escapeHtml(truncatedQuote)}"
`;
composeModal.querySelector('.compose-close')?.addEventListener('click', () => {
composeModal?.remove();
composeModal = null;
});
composeModal.querySelector('.btn-cancel')?.addEventListener('click', () => {
composeModal?.remove();
composeModal = null;
});
const textarea = composeModal.querySelector(
'.inline-compose-textarea'
) as HTMLTextAreaElement;
const submitBtn = composeModal.querySelector('.btn-submit') as HTMLButtonElement;
submitBtn.addEventListener('click', async () => {
const text = textarea?.value.trim();
if (!text) return;
submitBtn.disabled = true;
submitBtn.textContent = 'Posting...';
try {
const res = await sendMessage('createAnnotation', {
url: window.location.href,
title: document.title,
text,
selector: { type: 'TextQuoteSelector', exact: quoteText },
});
if (!res.success) {
throw new Error(res.error || 'Unknown error');
}
showToast('Annotation created!', 'success');
composeModal?.remove();
composeModal = null;
setTimeout(() => fetchAnnotations(), 500);
} catch (error) {
console.error('Failed to create annotation:', error);
showToast('Failed to create annotation', 'error');
submitBtn.disabled = false;
submitBtn.textContent = 'Post';
}
});
container.appendChild(composeModal);
setTimeout(() => textarea?.focus(), 100);
}
browser.runtime.onMessage.addListener((message: any) => {
if (message.type === 'SHOW_INLINE_ANNOTATE' && message.data?.selector?.exact) {
showComposeModal(message.data.selector.exact);
}
if (message.type === 'REFRESH_ANNOTATIONS') {
fetchAnnotations();
}
if (message.type === 'SCROLL_TO_TEXT' && message.text) {
scrollToText(message.text);
}
if (message.type === 'GET_SELECTION') {
const selection = window.getSelection();
const text = selection?.toString().trim() || '';
return Promise.resolve({ text });
}
});
function scrollToText(text: string) {
if (!text || text.length < 10) return;
const searchText = text.slice(0, 150);
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null);
let node: Text | null;
while ((node = walker.nextNode() as Text | null)) {
const content = node.textContent || '';
const index = content.indexOf(searchText.slice(0, 50));
if (index !== -1) {
const range = document.createRange();
range.setStart(node, index);
range.setEnd(node, Math.min(index + searchText.length, content.length));
const rect = range.getBoundingClientRect();
const scrollY = window.scrollY + rect.top - window.innerHeight / 3;
window.scrollTo({ top: scrollY, behavior: 'smooth' });
const highlight = document.createElement('mark');
highlight.style.cssText =
'background: #6366f1; color: white; padding: 2px 0; border-radius: 2px; transition: background 0.5s;';
range.surroundContents(highlight);
setTimeout(() => {
highlight.style.background = 'transparent';
highlight.style.color = 'inherit';
setTimeout(() => {
const parent = highlight.parentNode;
if (parent) {
parent.replaceChild(
document.createTextNode(highlight.textContent || ''),
highlight
);
parent.normalize();
}
}, 500);
}, 1500);
return;
}
}
}
function showToast(message: string, type: 'success' | 'error' = 'success') {
if (!shadowRoot) return;
const container = shadowRoot.getElementById('margin-overlay-container');
if (!container) return;
container.querySelectorAll('.margin-toast').forEach((el) => el.remove());
const toast = document.createElement('div');
toast.className = `margin-toast ${type === 'success' ? 'toast-success' : ''}`;
toast.innerHTML = `