feat: cleanup + screenshot buttons in chat toolbar (not just inspector)

Quick actions toolbar (🧹 Cleanup, 📸 Screenshot) now appears above the chat
input, always visible. Both inspector and chat buttons share runCleanup() and
runScreenshot() helper functions. Clicking either set shows loading state on
both simultaneously.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-03-29 23:27:42 -07:00
parent fc606515b6
commit 92adc71bbc
3 changed files with 124 additions and 64 deletions

View File

@@ -590,6 +590,59 @@ body::after {
} }
/* ─── Command Bar ─────────────────────────────────────── */ /* ─── Command Bar ─────────────────────────────────────── */
/* ─── Quick Actions Toolbar ─────────────────────────────── */
.quick-actions {
display: flex;
gap: 6px;
padding: 4px 8px;
background: var(--bg-surface);
border-top: 1px solid var(--border-subtle);
flex-shrink: 0;
}
.quick-action-btn {
display: flex;
align-items: center;
gap: 4px;
height: 26px;
padding: 0 10px;
background: none;
border: 1px solid var(--zinc-600);
border-radius: var(--radius-sm);
color: var(--text-label);
font-family: var(--font-system);
font-size: 11px;
cursor: pointer;
transition: all 150ms;
}
.quick-action-btn:hover {
background: rgba(255, 255, 255, 0.05);
color: var(--text-body);
border-color: var(--zinc-400);
}
.quick-action-btn:active {
transform: scale(0.96);
}
.quick-action-btn.loading {
pointer-events: none;
opacity: 0.5;
}
.quick-action-btn.loading::after {
content: '';
display: inline-block;
width: 10px;
height: 10px;
border: 2px solid var(--zinc-600);
border-top-color: var(--amber-400);
border-radius: 50%;
animation: spin 0.6s linear infinite;
}
.command-bar { .command-bar {
display: flex; display: flex;
align-items: center; align-items: center;

View File

@@ -136,6 +136,12 @@
Browser co-pilot &mdash; controls this browser, reports back to your workspace Browser co-pilot &mdash; controls this browser, reports back to your workspace
</div> </div>
<!-- Quick Actions Toolbar -->
<div class="quick-actions" id="quick-actions">
<button id="chat-cleanup-btn" class="quick-action-btn" title="Remove ads, banners, popups">🧹 Cleanup</button>
<button id="chat-screenshot-btn" class="quick-action-btn" title="Take a screenshot">📸 Screenshot</button>
</div>
<!-- Command Bar --> <!-- Command Bar -->
<div class="command-bar"> <div class="command-bar">
<button class="stop-btn" id="stop-agent-btn" title="Stop agent" style="display: none;">&#x25A0;</button> <button class="stop-btn" id="stop-agent-btn" title="Stop agent" style="display: none;">&#x25A0;</button>

View File

@@ -1149,17 +1149,14 @@ inspectorSendBtn.addEventListener('click', () => {
chrome.runtime.sendMessage({ type: 'sidebar-command', message }); chrome.runtime.sendMessage({ type: 'sidebar-command', message });
}); });
// ─── Cleanup Button ───────────────────────────────────────────── // ─── Quick Action Helpers (shared between chat toolbar + inspector) ──
const inspectorCleanupBtn = document.getElementById('inspector-cleanup-btn'); async function runCleanup(...buttons) {
if (inspectorCleanupBtn) {
inspectorCleanupBtn.addEventListener('click', async () => {
if (inspectorCleanupBtn.classList.contains('loading')) return;
if (!serverUrl || !serverToken) { if (!serverUrl || !serverToken) {
addChatEntry({ type: 'notification', message: 'Not connected to browse server' }); addChatEntry({ type: 'notification', message: 'Not connected to browse server' });
return; return;
} }
inspectorCleanupBtn.classList.add('loading'); buttons.forEach(b => b?.classList.add('loading'));
try { try {
const resp = await fetch(`${serverUrl}/command`, { const resp = await fetch(`${serverUrl}/command`, {
method: 'POST', method: 'POST',
@@ -1170,8 +1167,7 @@ if (inspectorCleanupBtn) {
const text = await resp.text(); const text = await resp.text();
if (resp.ok) { if (resp.ok) {
addChatEntry({ type: 'notification', message: text || 'Page cleaned up' }); addChatEntry({ type: 'notification', message: text || 'Page cleaned up' });
// Reset inspector — selected element may have been removed if (typeof inspectorShowEmpty === 'function') inspectorShowEmpty();
inspectorShowEmpty();
} else { } else {
const err = JSON.parse(text).error || 'Cleanup failed'; const err = JSON.parse(text).error || 'Cleanup failed';
addChatEntry({ type: 'notification', message: 'Error: ' + err }); addChatEntry({ type: 'notification', message: 'Error: ' + err });
@@ -1179,22 +1175,16 @@ if (inspectorCleanupBtn) {
} catch (err) { } catch (err) {
addChatEntry({ type: 'notification', message: 'Cleanup failed: ' + err.message }); addChatEntry({ type: 'notification', message: 'Cleanup failed: ' + err.message });
} finally { } finally {
inspectorCleanupBtn.classList.remove('loading'); buttons.forEach(b => b?.classList.remove('loading'));
} }
});
} }
// ─── Screenshot Button ────────────────────────────────────────── async function runScreenshot(...buttons) {
const inspectorScreenshotBtn = document.getElementById('inspector-screenshot-btn');
if (inspectorScreenshotBtn) {
inspectorScreenshotBtn.addEventListener('click', async () => {
if (inspectorScreenshotBtn.classList.contains('loading')) return;
if (!serverUrl || !serverToken) { if (!serverUrl || !serverToken) {
addChatEntry({ type: 'notification', message: 'Not connected to browse server' }); addChatEntry({ type: 'notification', message: 'Not connected to browse server' });
return; return;
} }
inspectorScreenshotBtn.classList.add('loading'); buttons.forEach(b => b?.classList.add('loading'));
try { try {
const resp = await fetch(`${serverUrl}/command`, { const resp = await fetch(`${serverUrl}/command`, {
method: 'POST', method: 'POST',
@@ -1212,11 +1202,22 @@ if (inspectorScreenshotBtn) {
} catch (err) { } catch (err) {
addChatEntry({ type: 'notification', message: 'Screenshot failed: ' + err.message }); addChatEntry({ type: 'notification', message: 'Screenshot failed: ' + err.message });
} finally { } finally {
inspectorScreenshotBtn.classList.remove('loading'); buttons.forEach(b => b?.classList.remove('loading'));
} }
});
} }
// ─── Wire up all cleanup/screenshot buttons (inspector + chat toolbar) ──
const inspectorCleanupBtn = document.getElementById('inspector-cleanup-btn');
const inspectorScreenshotBtn = document.getElementById('inspector-screenshot-btn');
const chatCleanupBtn = document.getElementById('chat-cleanup-btn');
const chatScreenshotBtn = document.getElementById('chat-screenshot-btn');
if (inspectorCleanupBtn) inspectorCleanupBtn.addEventListener('click', () => runCleanup(inspectorCleanupBtn, chatCleanupBtn));
if (inspectorScreenshotBtn) inspectorScreenshotBtn.addEventListener('click', () => runScreenshot(inspectorScreenshotBtn, chatScreenshotBtn));
if (chatCleanupBtn) chatCleanupBtn.addEventListener('click', () => runCleanup(chatCleanupBtn, inspectorCleanupBtn));
if (chatScreenshotBtn) chatScreenshotBtn.addEventListener('click', () => runScreenshot(chatScreenshotBtn, inspectorScreenshotBtn));
// ─── Section Toggles ──────────────────────────────────────────── // ─── Section Toggles ────────────────────────────────────────────
document.querySelectorAll('.inspector-section-toggle').forEach(toggle => { document.querySelectorAll('.inspector-section-toggle').forEach(toggle => {