feat: zero-friction side panel — auto-open on install, pill is clickable

Three changes to eliminate manual side panel setup:
- Auto-open side panel on extension install/update (onInstalled listener)
- gstack pill (bottom-right) is now clickable — opens the side panel
- Pill has pointer-events: auto so clicks always register (was: none)

User no longer needs to find the puzzle piece icon, pin the extension,
or know the side panel exists. It opens automatically on first launch
and can be re-opened by clicking the floating gstack pill.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-03-22 19:25:52 -07:00
parent 4e70c69d10
commit 08356929b3
3 changed files with 28 additions and 2 deletions
+21
View File
@@ -172,6 +172,14 @@ chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
return true;
}
// Open side panel from content script pill click
if (msg.type === 'openSidePanel') {
if (chrome.sidePanel?.open && sender.tab) {
chrome.sidePanel.open({ tabId: sender.tab.id }).catch(() => {});
}
return;
}
// Sidebar → browse server command proxy
if (msg.type === 'command') {
executeCommand(msg.command, msg.args).then(result => sendResponse(result));
@@ -207,6 +215,19 @@ if (chrome.sidePanel && chrome.sidePanel.setPanelBehavior) {
chrome.sidePanel.setPanelBehavior({ openPanelOnActionClick: true }).catch(() => {});
}
// Auto-open side panel on install/update — zero friction
chrome.runtime.onInstalled.addListener(async () => {
// Small delay to let the browser window fully initialize
setTimeout(async () => {
try {
const [win] = await chrome.windows.getAll({ windowTypes: ['normal'] });
if (win && chrome.sidePanel?.open) {
await chrome.sidePanel.open({ windowId: win.id });
}
} catch {}
}, 1000);
});
// ─── Startup ────────────────────────────────────────────────────
loadPort().then(() => {
+2 -2
View File
@@ -26,14 +26,14 @@
font-size: 11px;
font-weight: 500;
letter-spacing: 0.02em;
pointer-events: none;
pointer-events: auto;
cursor: pointer;
transition: opacity 0.5s ease;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.4);
}
#gstack-status-pill:hover {
opacity: 1 !important;
pointer-events: auto;
}
.gstack-pill-dot {
+5
View File
@@ -19,6 +19,11 @@ function showStatusPill(connected, refs) {
if (!statusPill) {
statusPill = document.createElement('div');
statusPill.id = 'gstack-status-pill';
statusPill.style.cursor = 'pointer';
statusPill.addEventListener('click', () => {
// Ask background to open the side panel
chrome.runtime.sendMessage({ type: 'openSidePanel' });
});
document.body.appendChild(statusPill);
}