theseus/bundled-addons/screenshot/index.js
Local Dev 5642959eca feat(theseus/screenshot): bundled screenshot add-on (visible / full page / region)
New capture-tab capability on the addon-host, and the screenshot add-on
uses it to expose three modes in a sidebar launcher panel:

- Visible viewport: Electron's WebContents.capturePage() on the active tab
- Full scrollable page: temp-resize the tab view to document.scrollHeight,
  capturePage, restore
- Region: preload overlays a translucent selection div, tracks mousedown /
  move / up, sends the rect back; main takes the visible capture and
  crops via nativeImage.crop({x,y,width,height})

Saves land in the user's Downloads folder via session.downloadURL — same
pipeline as any file download, so the download chip picks them up.
Filename: theseus-screenshot-<host>-<ISO date>.png. JPEG option for
smaller files.

A follow-up task (task_b9608dc6) reworks this to open captures in a
full-tab editor with crop / draw / annotate / undo / copy-to-clipboard
instead of the current bare launcher.
2026-09-07 00:18:48 +02:00

49 lines
2.1 KiB
JavaScript

// Screenshot — capture the active tab. The panel drives everything through
// two messages ("capture" and "save"); main-side capture-tab does the actual
// pixel work. This module is a thin router.
const fs = require("node:fs");
const path = require("node:path");
module.exports = {
activate(api) {
api.registerSidebarPanel({
id: "main",
title: "Screenshot",
icon: "📸",
page: "panel.html",
});
// Region-select overlay source, loaded once at activation. The panel
// triggers region mode; main injects this into the tab and awaits the
// rect it resolves with. Keeping the DOM code in a sibling file (not a
// JS string in main) lets someone edit the overlay UX without touching
// the browser core.
let overlaySource = "";
try { overlaySource = fs.readFileSync(path.join(api.folder, "panel-preload.js"), "utf8"); }
catch (e) { api.log("panel-preload.js not readable:", e?.message); }
api.onMessage("capture", async (payload) => {
const mode = String(payload?.mode || "visible");
const format = payload?.format === "jpeg" ? "jpeg" : "png";
const quality = Number(payload?.quality) || 90;
const opts = { mode, format, quality };
if (mode === "region") opts.overlaySource = overlaySource;
return api.captureTab(opts);
});
api.onMessage("save", async (payload) => {
const dataUrl = String(payload?.dataUrl || "");
const host = String(payload?.host || "tab");
const format = payload?.format === "jpeg" ? "jpeg" : "png";
const ext = format === "jpeg" ? "jpg" : "png";
// ISO date, but with the colons Windows won't accept in filenames swapped
// out. Second precision is enough; the filename is human-oriented.
const iso = new Date().toISOString().replace(/[:.]/g, "-").replace(/-\d{3}Z$/, "Z");
const safeHost = (host || "tab").replace(/[^a-z0-9._-]+/gi, "_") || "tab";
const filename = `theseus-screenshot-${safeHost}-${iso}.${ext}`;
return api.saveCapture({ dataUrl, filename });
});
api.log("registered screenshot panel");
},
};