Skip to content

Commit b47a7dc

Browse files
committed
[frontend] context menu for images
1 parent 64a2480 commit b47a7dc

File tree

1 file changed

+80
-4
lines changed

1 file changed

+80
-4
lines changed

frontend/src/Tab.tsx

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { createState } from "dreamland/core";
22
import { StatefulClass } from "./StatefulClass";
3-
import { scramjet } from "./main";
3+
import { browser, scramjet } from "./main";
44
import {
55
addHistoryListeners,
66
History,
@@ -107,9 +107,44 @@ export class Tab extends StatefulClass {
107107
}
108108
}
109109

110-
function pageContextItems(client: ScramjetClient, tab: Tab) {
111-
let frame = tab.frame;
110+
function copyImageToClipboard(img: HTMLImageElement) {
111+
if (!img.complete || !img.naturalWidth) {
112+
console.error("Image not loaded yet");
113+
return;
114+
}
115+
116+
const canvas = document.createElement("canvas");
117+
canvas.width = img.naturalWidth;
118+
canvas.height = img.naturalHeight;
119+
120+
const ctx = canvas.getContext("2d");
121+
if (!ctx) {
122+
console.error("Failed to get canvas context");
123+
return;
124+
}
125+
126+
ctx.drawImage(img, 0, 0);
112127

128+
canvas.toBlob((blob) => {
129+
if (blob) {
130+
navigator.clipboard
131+
.write([
132+
new ClipboardItem({
133+
"image/png": blob,
134+
}),
135+
])
136+
.then(() => {
137+
console.log("Image copied to clipboard");
138+
})
139+
.catch((err) => {
140+
console.error("Failed to copy image to clipboard", err);
141+
});
142+
}
143+
}, "image/png");
144+
}
145+
146+
function pageContextItems(client: ScramjetClient, tab: Tab, e: MouseEvent) {
147+
console.log(e.target);
113148
const selection = client.global.getSelection();
114149
if (selection && selection.toString().length > 0) {
115150
return [
@@ -135,6 +170,43 @@ function pageContextItems(client: ScramjetClient, tab: Tab) {
135170
];
136171
}
137172

173+
let target = e.target;
174+
let view = e.view!.window;
175+
// need to use e.view here they're different objects
176+
if (target && target instanceof view.HTMLImageElement) {
177+
return [
178+
{
179+
label: "Open Image in New Tab",
180+
action: () => {
181+
// TODO: this is broken lol
182+
const imgUrl = scramjet.decodeUrl(target.src);
183+
if (imgUrl) {
184+
let newTab = browser.newTab();
185+
newTab.pushNavigate(new URL(imgUrl));
186+
}
187+
},
188+
},
189+
{
190+
label: "Copy Image URL",
191+
action: () => {
192+
navigator.clipboard.writeText(scramjet.decodeUrl(target.src));
193+
},
194+
},
195+
{
196+
label: "Copy Image",
197+
action: () => {
198+
copyImageToClipboard(target);
199+
},
200+
},
201+
{
202+
label: "Save Image As...",
203+
action: () => {
204+
// TODO
205+
},
206+
},
207+
];
208+
}
209+
138210
return [
139211
{
140212
label: "Back",
@@ -183,7 +255,11 @@ function injectContextMenu(client: ScramjetClient, tab: Tab) {
183255
xoff += x;
184256
yoff += y;
185257

186-
createMenu(xoff + e.pageX, yoff + e.pageY, pageContextItems(client, tab));
258+
createMenu(
259+
xoff + e.pageX,
260+
yoff + e.pageY,
261+
pageContextItems(client, tab, e)
262+
);
187263
e.preventDefault();
188264
});
189265
}

0 commit comments

Comments
 (0)