Skip to content

Commit 6bff3d4

Browse files
committed
feat: Add an option to open TS cards in a popup window instead of iframe modal
1 parent 0c1c64c commit 6bff3d4

File tree

6 files changed

+140
-7
lines changed

6 files changed

+140
-7
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport"
6+
content="width=device-width, initial-scale=1.0" />
7+
<title>TLink Options</title>
8+
<meta name="manifest.open_in_tab" content="false" />
9+
<meta name="manifest.browser_style" content="true" />
10+
</head>
11+
<body>
12+
<label>
13+
<input type="checkbox" id="use_popup_window" />
14+
Use a popup window to show Tapp action cards
15+
</label>
16+
<br/><br/>
17+
<div id="status"></div>
18+
<br/>
19+
<button id="save">Save</button>
20+
<script type="module" src="options.js"></script>
21+
</body>
22+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Saves options to chrome.storage
2+
const saveOptions = () => {
3+
const use_popup_window = document.getElementById('use_popup_window').checked;
4+
5+
chrome.storage.sync.set(
6+
{ use_popup_window },
7+
() => {
8+
// Update status to let user know options were saved.
9+
const status = document.getElementById('status');
10+
status.textContent = 'Options saved.';
11+
setTimeout(() => {
12+
status.textContent = '';
13+
}, 750);
14+
}
15+
);
16+
};
17+
18+
// Restores select box and checkbox state using the preferences
19+
// stored in chrome.storage.
20+
const restoreOptions = () => {
21+
chrome.storage.sync.get(
22+
{ use_popup_window: false },
23+
(items) => {
24+
document.getElementById('use_popup_window').checked = items.use_popup_window;
25+
}
26+
);
27+
};
28+
29+
document.addEventListener('DOMContentLoaded', restoreOptions);
30+
document.getElementById('save').addEventListener('click', saveOptions);

apps/extension/entrypoints/twitter-observer.content/twitter-observer.tsx

+13-4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import "@repo/tlinks/index.css"
44
import { useEffect, useState } from "react"
55
import "~/assets/style.css"
66
import {AbstractActionComponent, TokenscriptCardMetadata} from "@repo/tlinks";
7+
import {openTsPopupWindow} from "@/lib/open-ts-popup-window";
78

89
export const TwitterObserver = () => {
910
const [dAppUrl, setDAppUrl] = useState("")
@@ -18,11 +19,19 @@ export const TwitterObserver = () => {
1819
connect: () => chrome.runtime.sendMessage({ type: "connect" }),
1920
getConnectedAccount: () =>
2021
chrome.runtime.sendMessage({ type: "getConnectedAccount" }),
21-
interceptHandlePost: (component: AbstractActionComponent) => {
22+
interceptHandlePost: async (component: AbstractActionComponent) => {
2223
if (isTokenScriptViewerUrl(component.href)) {
23-
setTsMetadata(component.tsMetadata as TokenscriptCardMetadata)
24-
setDAppUrl(component.href)
25-
iframePopupRef.current?.setOpen(true)
24+
25+
const options = await chrome.storage.sync.get({ use_popup_window: false });
26+
27+
if (options.use_popup_window){
28+
openTsPopupWindow(component.href, component.tsMetadata);
29+
} else {
30+
setTsMetadata(component.tsMetadata as TokenscriptCardMetadata)
31+
setDAppUrl(component.href)
32+
iframePopupRef.current?.setOpen(true)
33+
}
34+
2635
return true
2736
} else {
2837
return false

apps/extension/lib/handle-tlink-api.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ async function handleTlinkApiViaTSViewerWindow(method: string, payload: any){
6060
});
6161
}
6262

63-
function popupCenter(url: string, title: string, w: number, h: number) {
63+
export function popupCenter(url: string, title: string, w: number, h: number) {
6464
const left = (screen.width/2)-(w/2);
6565
const top = (screen.height/2)-(h/2);
6666
return window.open(url, title, 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=yes, copyhistory=no, width='+w+', height='+h+', top='+top+', left='+left);
+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import {handleTlinkApiRequest, popupCenter} from "@/lib/handle-tlink-api.ts";
2+
import {TokenscriptCardMetadata} from "@repo/tlinks/src";
3+
4+
export function openTsPopupWindow(dAppUrl: string, tsMetadata: TokenscriptCardMetadata){
5+
6+
let popup;
7+
8+
const handleMessage = async (event: MessageEvent) => {
9+
10+
// We only proxy messages that originate from the child iframe
11+
if (!popup || event.source !== popup) {
12+
return
13+
}
14+
15+
console.log("Processing message from popup", event, popup);
16+
17+
if (event.data?.type === "TLINK_API_REQUEST") {
18+
popup.postMessage(
19+
{
20+
type: "TLINK_API_RESPONSE",
21+
source: "TLINK_API_RESPONSE",
22+
data: {
23+
uid: event.data.data.uid,
24+
method: event.data.data.method,
25+
response: await handleTlinkApiRequest(
26+
event.data.data.method,
27+
event.data.data.payload
28+
)
29+
}
30+
},
31+
"*"
32+
)
33+
}
34+
35+
if (event.data?.jsonrpc) {
36+
const resp = await chrome.runtime.sendMessage({
37+
type: "rpc",
38+
data: event.data
39+
})
40+
41+
sendResponse(event.data, resp)
42+
}
43+
44+
function sendResponse(
45+
messageData: MessageEvent["data"],
46+
response: any | null
47+
) {
48+
const data = messageData
49+
50+
if (response?.error) {
51+
data.error = response.error
52+
} else {
53+
data.result = response.result
54+
}
55+
56+
popup!!.postMessage(
57+
data,
58+
"*"
59+
)
60+
}
61+
}
62+
63+
const width = tsMetadata.fullScreen ? Math.round(screen.width * 0.9) : 550;
64+
const height = tsMetadata.fullScreen ? Math.round(screen.height * 0.9) : 800;
65+
66+
popup = popupCenter(dAppUrl, "", width, height);
67+
68+
window.addEventListener("message", handleMessage);
69+
70+
if (!popup)
71+
throw new Error("Failed to open the popup window");
72+
}

packages/tlinks/src/api/ActionConfig.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export interface ActionAdapter {
3939
| { signature: string }
4040
| { error: string | { code: number; message: string } }
4141
>;
42-
interceptHandlePost?: (href: AbstractActionComponent) => boolean;
42+
interceptHandlePost?: (href: AbstractActionComponent) => boolean|Promise<boolean>;
4343
tsIframeRenderer?: (props: { websiteUrl: string }) => JSX.Element | null;
4444
}
4545

@@ -74,7 +74,7 @@ export class ActionConfig implements ActionAdapter {
7474
}
7575
}
7676

77-
interceptHandlePost(component: AbstractActionComponent) {
77+
async interceptHandlePost(component: AbstractActionComponent) {
7878
return this.adapter.interceptHandlePost?.(component) || false;
7979
}
8080

0 commit comments

Comments
 (0)