Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 27 additions & 12 deletions src/chrome/src/content/selection-shortcut.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,13 +161,13 @@ host.lang = localization.locale;
if (ancestor?.closest?.('input, textarea')) return null;

const rects = Array.from(range.getClientRects()).filter((rect) => rect.width > 0 && rect.height > 0);
const rect = rects.at(-1) || range.getBoundingClientRect();
const visibleRects = collectVisibleHighlightRects(rects);
const rect = visibleRects[0] || rects[0] || range.getBoundingClientRect();
if (!rect || (!rect.width && !rect.height)) return null;
const highlightRects = collectVisibleHighlightRects(rects);
return {
text,
rect: serializeRect(rect),
rects: (highlightRects.length ? highlightRects : [rect]).map(serializeRect),
rects: (visibleRects.length ? visibleRects : [rect]).map(serializeRect),
};
}

Expand All @@ -194,12 +194,12 @@ host.lang = localization.locale;
}
.shortcut {
position:fixed; width:${BUTTON_SIZE}px; height:${BUTTON_SIZE}px; display:grid;
place-items:center; padding:0; border:1px solid rgba(108,99,255,.34);
border-radius:14px; background:var(--bg); color:var(--accent);
box-shadow:0 10px 26px rgba(35,30,95,.22),0 2px 7px rgba(35,30,95,.12);
place-items:center; padding:0; border:1px solid rgba(23,23,34,.14);
border-radius:14px; background:#fff; color:#171722;
box-shadow:0 9px 20px rgba(23,23,34,.16),0 2px 5px rgba(23,23,34,.1);
cursor:pointer; pointer-events:auto; transition:transform 130ms ease,box-shadow 130ms ease;
}
.shortcut:hover { transform:translateY(-1px) scale(1.03); box-shadow:0 13px 30px rgba(35,30,95,.27),0 3px 8px rgba(35,30,95,.14); }
.shortcut:hover { transform:translateY(-1px) scale(1.03); box-shadow:0 12px 25px rgba(23,23,34,.2),0 3px 7px rgba(23,23,34,.12); }
.shortcut-icon {
display:block; font:700 25px/1 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;
transform:translateY(-1px);
Expand Down Expand Up @@ -256,7 +256,8 @@ host.lang = localization.locale;
width:auto; margin-left:auto; padding:5px 8px;
color:var(--muted); font-size:12px; line-height:1.25;
}
.shortcut:focus-visible,.action:focus-visible,.hide:focus-visible,.send:focus-visible,textarea:focus-visible,.context-option input:focus-visible {
.shortcut:focus-visible { outline:3px solid rgba(23,23,34,.24); outline-offset:2px; }
.action:focus-visible,.hide:focus-visible,.send:focus-visible,textarea:focus-visible,.context-option input:focus-visible {
outline:3px solid rgba(108,99,255,.34); outline-offset:2px;
}
.toast {
Expand All @@ -275,10 +276,10 @@ host.lang = localization.locale;
@media (prefers-reduced-motion:reduce) { .shortcut { transition:none; } }
</style>
<div class="selection-highlights" aria-hidden="true"></div>
<button class="shortcut" type="button" aria-label="Ask WebBrain about selected text" title="Ask WebBrain" hidden>
<button class="shortcut" type="button" aria-label="Add to chat" title="Add to chat" hidden>
<span class="shortcut-icon" aria-hidden="true">?</span>
</button>
<div class="popup" role="dialog" aria-label="Ask WebBrain about selected text" hidden>
<div class="popup" role="dialog" aria-label="Add to chat" hidden>
<div class="main-view">
<div class="actions">
<button class="action" type="button" data-action="summarize">
Expand Down Expand Up @@ -373,12 +374,20 @@ host.lang = localization.locale;
(document.documentElement || document.body).appendChild(host);
}

function getVisibleSelectionBottom() {
if (!snapshot) return 0;
return (snapshot.rects || []).reduce(
(bottom, selectionRect) => Math.max(bottom, selectionRect.bottom),
snapshot.rect.bottom,
);
}

function positionShortcut() {
if (!snapshot || !shortcut) return;
const rect = snapshot.rect;
let left = rect.left + rect.width / 2 - BUTTON_SIZE / 2;
let top = rect.bottom + 8;
if (top + BUTTON_SIZE > window.innerHeight - GAP) top = rect.top - BUTTON_SIZE - 8;
let top = rect.top - BUTTON_SIZE - GAP;
if (top < GAP) top = getVisibleSelectionBottom() + GAP;
left = clamp(left, GAP, Math.max(GAP, window.innerWidth - BUTTON_SIZE - GAP));
top = clamp(top, GAP, Math.max(GAP, window.innerHeight - BUTTON_SIZE - GAP));
shortcut.style.left = `${Math.round(left)}px`;
Expand Down Expand Up @@ -605,6 +614,12 @@ host.lang = localization.locale;
highlightRectCount: highlightLayer?.childElementCount || 0,
toastVisible: !!toast && !toast.hidden,
shortcutRect: shortcut && !shortcut.hidden ? shortcut.getBoundingClientRect().toJSON() : null,
selectionRect: snapshot?.rect || null,
selectionBottom: snapshot ? getVisibleSelectionBottom() : null,
shortcutLabel: shortcut?.getAttribute('aria-label') || '',
shortcutBackground: shortcut ? getComputedStyle(shortcut).backgroundColor : '',
shortcutColor: shortcut ? getComputedStyle(shortcut).color : '',
shortcutBoxShadow: shortcut ? getComputedStyle(shortcut).boxShadow : '',
summarizeRect: popup && !popup.hidden
? shadow.querySelector('[data-action="summarize"]')?.getBoundingClientRect().toJSON() || null
: null,
Expand Down
46 changes: 23 additions & 23 deletions src/chrome/src/selection-shortcut-i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

const STRINGS = Object.freeze({
en: {
askSelection: 'Ask WebBrain about this',
askSelection: 'Add to chat',
openChat: 'Open WebBrain to chat',
summarize: 'Summarize',
explain: 'Explain',
Expand All @@ -23,7 +23,7 @@ const STRINGS = Object.freeze({
sendFailed: 'Could not send to WebBrain. Try the right-click menu instead.',
},
zh: {
askSelection: '向 WebBrain 询问此内容',
askSelection: '添加到聊天',
openChat: '打开 WebBrain 进行对话',
summarize: '总结',
explain: '解释',
Expand All @@ -41,7 +41,7 @@ const STRINGS = Object.freeze({
sendFailed: '无法发送至 WebBrain。请尝试使用右键菜单。',
},
ar: {
askSelection: 'اسأل WebBrain عن هذا',
askSelection: 'إضافة إلى الدردشة',
openChat: 'افتح WebBrain للدردشة',
summarize: 'تلخيص',
explain: 'شرح',
Expand All @@ -59,7 +59,7 @@ const STRINGS = Object.freeze({
sendFailed: 'تعذر الإرسال إلى WebBrain. جرّب قائمة النقر بزر الماوس الأيمن.',
},
bn: {
askSelection: 'এটি সম্পর্কে WebBrain-কে জিজ্ঞাসা করুন',
askSelection: 'চ্যাটে যোগ করুন',
openChat: 'চ্যাট করতে WebBrain খুলুন',
summarize: 'সারসংক্ষেপ করুন',
explain: 'ব্যাখ্যা করুন',
Expand All @@ -77,7 +77,7 @@ const STRINGS = Object.freeze({
sendFailed: 'WebBrain-এ পাঠানো যায়নি। ডান-ক্লিক মেনু ব্যবহার করে দেখুন।',
},
de: {
askSelection: 'WebBrain hierzu fragen',
askSelection: 'Zum Chat hinzufügen',
openChat: 'WebBrain zum Chatten öffnen',
summarize: 'Zusammenfassen',
explain: 'Erklären',
Expand All @@ -95,7 +95,7 @@ const STRINGS = Object.freeze({
sendFailed: 'Senden an WebBrain fehlgeschlagen. Versuche stattdessen das Kontextmenü.',
},
es: {
askSelection: 'Preguntar a WebBrain sobre esto',
askSelection: 'Añadir al chat',
openChat: 'Abrir WebBrain para chatear',
summarize: 'Resumir',
explain: 'Explicar',
Expand All @@ -113,7 +113,7 @@ const STRINGS = Object.freeze({
sendFailed: 'No se pudo enviar a WebBrain. Prueba el menú contextual.',
},
fa: {
askSelection: 'درباره این از WebBrain بپرسید',
askSelection: 'افزودن به چت',
openChat: 'WebBrain را برای گفتگو باز کنید',
summarize: 'خلاصه‌سازی',
explain: 'توضیح',
Expand All @@ -131,7 +131,7 @@ const STRINGS = Object.freeze({
sendFailed: 'ارسال به WebBrain ممکن نشد. از منوی کلیک راست استفاده کنید.',
},
fr: {
askSelection: 'Interroger WebBrain à ce sujet',
askSelection: 'Ajouter au chat',
openChat: 'Ouvrir WebBrain pour discuter',
summarize: 'Résumer',
explain: 'Expliquer',
Expand All @@ -149,7 +149,7 @@ const STRINGS = Object.freeze({
sendFailed: 'Impossible d’envoyer à WebBrain. Essayez le menu contextuel.',
},
he: {
askSelection: 'לשאול את WebBrain על זה',
askSelection: 'הוספה לצ׳אט',
openChat: 'פתיחת WebBrain לצ׳אט',
summarize: 'סיכום',
explain: 'הסבר',
Expand All @@ -167,7 +167,7 @@ const STRINGS = Object.freeze({
sendFailed: 'לא ניתן לשלוח אל WebBrain. נסו את תפריט הלחיצה הימנית.',
},
hi: {
askSelection: 'इसके बारे में WebBrain से पूछें',
askSelection: 'चैट में जोड़ें',
openChat: 'चैट के लिए WebBrain खोलें',
summarize: 'सारांश बनाएँ',
explain: 'समझाएँ',
Expand All @@ -185,7 +185,7 @@ const STRINGS = Object.freeze({
sendFailed: 'WebBrain को भेजा नहीं जा सका। राइट-क्लिक मेनू आज़माएँ।',
},
id: {
askSelection: 'Tanyakan ini kepada WebBrain',
askSelection: 'Tambahkan ke chat',
openChat: 'Buka WebBrain untuk mengobrol',
summarize: 'Ringkas',
explain: 'Jelaskan',
Expand All @@ -203,7 +203,7 @@ const STRINGS = Object.freeze({
sendFailed: 'Tidak dapat mengirim ke WebBrain. Coba menu klik kanan.',
},
ja: {
askSelection: 'この内容について WebBrain に質問',
askSelection: 'チャットに追加',
openChat: 'WebBrain を開いてチャット',
summarize: '要約',
explain: '説明',
Expand All @@ -221,7 +221,7 @@ const STRINGS = Object.freeze({
sendFailed: 'WebBrain に送信できませんでした。右クリックメニューをお試しください。',
},
ko: {
askSelection: '이 내용에 대해 WebBrain에 질문',
askSelection: '채팅에 추가',
openChat: 'WebBrain을 열어 채팅',
summarize: '요약',
explain: '설명',
Expand All @@ -239,7 +239,7 @@ const STRINGS = Object.freeze({
sendFailed: 'WebBrain으로 보낼 수 없습니다. 오른쪽 클릭 메뉴를 사용해 보세요.',
},
ms: {
askSelection: 'Tanya WebBrain tentang ini',
askSelection: 'Tambahkan pada sembang',
openChat: 'Buka WebBrain untuk berbual',
summarize: 'Ringkaskan',
explain: 'Terangkan',
Expand All @@ -257,7 +257,7 @@ const STRINGS = Object.freeze({
sendFailed: 'Tidak dapat menghantar ke WebBrain. Cuba menu klik kanan.',
},
nl: {
askSelection: 'WebBrain hierover vragen',
askSelection: 'Toevoegen aan chat',
openChat: 'WebBrain openen om te chatten',
summarize: 'Samenvatten',
explain: 'Uitleggen',
Expand All @@ -275,7 +275,7 @@ const STRINGS = Object.freeze({
sendFailed: 'Verzenden naar WebBrain is mislukt. Probeer het rechtermuisknopmenu.',
},
pl: {
askSelection: 'Zapytaj WebBrain o to',
askSelection: 'Dodaj do czatu',
openChat: 'Otwórz WebBrain, aby porozmawiać',
summarize: 'Podsumuj',
explain: 'Wyjaśnij',
Expand All @@ -293,7 +293,7 @@ const STRINGS = Object.freeze({
sendFailed: 'Nie udało się wysłać do WebBrain. Użyj menu pod prawym przyciskiem myszy.',
},
pt: {
askSelection: 'Perguntar ao WebBrain sobre isto',
askSelection: 'Adicionar ao chat',
openChat: 'Abrir o WebBrain para conversar',
summarize: 'Resumir',
explain: 'Explicar',
Expand All @@ -311,7 +311,7 @@ const STRINGS = Object.freeze({
sendFailed: 'Não foi possível enviar ao WebBrain. Tente o menu do botão direito.',
},
ru: {
askSelection: 'Спросить WebBrain об этом',
askSelection: 'Добавить в чат',
openChat: 'Открыть WebBrain для чата',
summarize: 'Кратко изложить',
explain: 'Объяснить',
Expand All @@ -329,7 +329,7 @@ const STRINGS = Object.freeze({
sendFailed: 'Не удалось отправить в WebBrain. Попробуйте контекстное меню.',
},
th: {
askSelection: 'ถาม WebBrain เกี่ยวกับสิ่งนี้',
askSelection: 'เพิ่มไปยังแชท',
openChat: 'เปิด WebBrain เพื่อแชต',
summarize: 'สรุป',
explain: 'อธิบาย',
Expand All @@ -347,7 +347,7 @@ const STRINGS = Object.freeze({
sendFailed: 'ส่งไปยัง WebBrain ไม่ได้ โปรดลองใช้เมนูคลิกขวา',
},
tl: {
askSelection: 'Itanong ito sa WebBrain',
askSelection: 'Idagdag sa chat',
openChat: 'Buksan ang WebBrain para makipag-chat',
summarize: 'Ibuod',
explain: 'Ipaliwanag',
Expand All @@ -365,7 +365,7 @@ const STRINGS = Object.freeze({
sendFailed: 'Hindi maipadala sa WebBrain. Subukan ang right-click menu.',
},
tr: {
askSelection: 'Bunu WebBrain’e sor',
askSelection: 'Sohbete ekle',
openChat: 'Sohbet için WebBrain’i aç',
summarize: 'Özetle',
explain: 'Açıkla',
Expand All @@ -383,7 +383,7 @@ const STRINGS = Object.freeze({
sendFailed: 'WebBrain’e gönderilemedi. Sağ tık menüsünü deneyin.',
},
uk: {
askSelection: 'Запитати WebBrain про це',
askSelection: 'Додати до чату',
openChat: 'Відкрити WebBrain для чату',
summarize: 'Підсумувати',
explain: 'Пояснити',
Expand All @@ -401,7 +401,7 @@ const STRINGS = Object.freeze({
sendFailed: 'Не вдалося надіслати до WebBrain. Спробуйте контекстне меню.',
},
vi: {
askSelection: 'Hỏi WebBrain về nội dung này',
askSelection: 'Thêm vào cuộc trò chuyện',
openChat: 'Mở WebBrain để trò chuyện',
summarize: 'Tóm tắt',
explain: 'Giải thích',
Expand Down
39 changes: 27 additions & 12 deletions src/firefox/src/content/selection-shortcut.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,13 +161,13 @@ host.lang = localization.locale;
if (ancestor?.closest?.('input, textarea')) return null;

const rects = Array.from(range.getClientRects()).filter((rect) => rect.width > 0 && rect.height > 0);
const rect = rects.at(-1) || range.getBoundingClientRect();
const visibleRects = collectVisibleHighlightRects(rects);
const rect = visibleRects[0] || rects[0] || range.getBoundingClientRect();
if (!rect || (!rect.width && !rect.height)) return null;
const highlightRects = collectVisibleHighlightRects(rects);
return {
text,
rect: serializeRect(rect),
rects: (highlightRects.length ? highlightRects : [rect]).map(serializeRect),
rects: (visibleRects.length ? visibleRects : [rect]).map(serializeRect),
};
}

Expand All @@ -194,12 +194,12 @@ host.lang = localization.locale;
}
.shortcut {
position:fixed; width:${BUTTON_SIZE}px; height:${BUTTON_SIZE}px; display:grid;
place-items:center; padding:0; border:1px solid rgba(108,99,255,.34);
border-radius:14px; background:var(--bg); color:var(--accent);
box-shadow:0 10px 26px rgba(35,30,95,.22),0 2px 7px rgba(35,30,95,.12);
place-items:center; padding:0; border:1px solid rgba(23,23,34,.14);
border-radius:14px; background:#fff; color:#171722;
box-shadow:0 9px 20px rgba(23,23,34,.16),0 2px 5px rgba(23,23,34,.1);
cursor:pointer; pointer-events:auto; transition:transform 130ms ease,box-shadow 130ms ease;
}
.shortcut:hover { transform:translateY(-1px) scale(1.03); box-shadow:0 13px 30px rgba(35,30,95,.27),0 3px 8px rgba(35,30,95,.14); }
.shortcut:hover { transform:translateY(-1px) scale(1.03); box-shadow:0 12px 25px rgba(23,23,34,.2),0 3px 7px rgba(23,23,34,.12); }
.shortcut-icon {
display:block; font:700 25px/1 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;
transform:translateY(-1px);
Expand Down Expand Up @@ -256,7 +256,8 @@ host.lang = localization.locale;
width:auto; margin-left:auto; padding:5px 8px;
color:var(--muted); font-size:12px; line-height:1.25;
}
.shortcut:focus-visible,.action:focus-visible,.hide:focus-visible,.send:focus-visible,textarea:focus-visible,.context-option input:focus-visible {
.shortcut:focus-visible { outline:3px solid rgba(23,23,34,.24); outline-offset:2px; }
.action:focus-visible,.hide:focus-visible,.send:focus-visible,textarea:focus-visible,.context-option input:focus-visible {
outline:3px solid rgba(108,99,255,.34); outline-offset:2px;
}
.toast {
Expand All @@ -275,10 +276,10 @@ host.lang = localization.locale;
@media (prefers-reduced-motion:reduce) { .shortcut { transition:none; } }
</style>
<div class="selection-highlights" aria-hidden="true"></div>
<button class="shortcut" type="button" aria-label="Ask WebBrain about selected text" title="Ask WebBrain" hidden>
<button class="shortcut" type="button" aria-label="Add to chat" title="Add to chat" hidden>
<span class="shortcut-icon" aria-hidden="true">?</span>
</button>
<div class="popup" role="dialog" aria-label="Ask WebBrain about selected text" hidden>
<div class="popup" role="dialog" aria-label="Add to chat" hidden>
<div class="main-view">
<div class="actions">
<button class="action" type="button" data-action="summarize">
Expand Down Expand Up @@ -373,12 +374,20 @@ host.lang = localization.locale;
(document.documentElement || document.body).appendChild(host);
}

function getVisibleSelectionBottom() {
if (!snapshot) return 0;
return (snapshot.rects || []).reduce(
(bottom, selectionRect) => Math.max(bottom, selectionRect.bottom),
snapshot.rect.bottom,
);
}

function positionShortcut() {
if (!snapshot || !shortcut) return;
const rect = snapshot.rect;
let left = rect.left + rect.width / 2 - BUTTON_SIZE / 2;
let top = rect.bottom + 8;
if (top + BUTTON_SIZE > window.innerHeight - GAP) top = rect.top - BUTTON_SIZE - 8;
let top = rect.top - BUTTON_SIZE - GAP;
if (top < GAP) top = getVisibleSelectionBottom() + GAP;
left = clamp(left, GAP, Math.max(GAP, window.innerWidth - BUTTON_SIZE - GAP));
top = clamp(top, GAP, Math.max(GAP, window.innerHeight - BUTTON_SIZE - GAP));
shortcut.style.left = `${Math.round(left)}px`;
Expand Down Expand Up @@ -605,6 +614,12 @@ host.lang = localization.locale;
highlightRectCount: highlightLayer?.childElementCount || 0,
toastVisible: !!toast && !toast.hidden,
shortcutRect: shortcut && !shortcut.hidden ? shortcut.getBoundingClientRect().toJSON() : null,
selectionRect: snapshot?.rect || null,
selectionBottom: snapshot ? getVisibleSelectionBottom() : null,
shortcutLabel: shortcut?.getAttribute('aria-label') || '',
shortcutBackground: shortcut ? getComputedStyle(shortcut).backgroundColor : '',
shortcutColor: shortcut ? getComputedStyle(shortcut).color : '',
shortcutBoxShadow: shortcut ? getComputedStyle(shortcut).boxShadow : '',
summarizeRect: popup && !popup.hidden
? shadow.querySelector('[data-action="summarize"]')?.getBoundingClientRect().toJSON() || null
: null,
Expand Down
Loading
Loading