Skip to content

Commit 224a51f

Browse files
committed
fix: stabilize menu injection
1 parent ca633f6 commit 224a51f

File tree

5 files changed

+168
-124
lines changed

5 files changed

+168
-124
lines changed

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@
2121
},
2222
"devDependencies": {
2323
"@pionxzh/eslint-config-ts": "^0.1.1",
24-
"@types/node": "^18.11.10",
24+
"@types/node": "^18.11.17",
2525
"cpy-cli": "^4.2.0",
26-
"eslint": "^8.29.0",
26+
"eslint": "^8.30.0",
2727
"husky": "^8.0.2",
2828
"lint-staged": "^13.1.0",
2929
"rimraf": "^3.0.2",
30-
"sass": "^1.56.1",
30+
"sass": "^1.57.0",
3131
"turbo": "^1.6.3",
32-
"typescript": "^4.9.3"
32+
"typescript": "^4.9.4"
3333
},
3434
"lint-staged": {
3535
"*.{js,jsx,ts,tsx}": "pnpm exec eslint"

packages/userscript/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
},
1818
"dependencies": {
1919
"html2canvas": "^1.4.1",
20-
"vite-plugin-monkey": "^2.7.3"
20+
"sentinel-js": "^0.0.5",
21+
"vite-plugin-monkey": "^2.10.0"
2122
},
2223
"devDependencies": {
2324
"vite": "^3.1.4"

packages/userscript/src/main.ts

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import html2canvas from 'html2canvas'
2+
import sentinel from 'sentinel-js'
23
import { chatGPTAvatarSVG, fileCode, iconCamera, iconCopy } from './icons'
34
import { copyToClipboard, downloadFile, downloadUrl, escapeHtml, getBase64FromImg, onloadSafe, sleep, timestamp } from './utils'
45
import templateHtml from './template.html?raw'
@@ -24,18 +25,13 @@ main()
2425

2526
function main() {
2627
onloadSafe(() => {
27-
const firstMenuItem = document.querySelector('nav > a')
28-
const container = firstMenuItem?.parentElement
29-
if (!firstMenuItem || !container) {
30-
console.error('Failed to locate the menu container element.')
31-
// alert('Failed to locate the menu container element. Please report this issue to the developer.')
28+
const nav = document.querySelector('nav')
29+
if (!nav) {
30+
console.error('Failed to locate the nav element. Please report this issue to the developer.')
31+
// alert('Failed to locate the nav element. Please report this issue to the developer.')
3232
return
3333
}
3434

35-
const divider = document.createElement('div')
36-
divider.className = 'border-b border-white/20'
37-
divider.style.marginBottom = '0.5rem'
38-
3935
const copyHtml = `${iconCopy}Copy Text`
4036
const copiedHtml = `${iconCopy}Copied`
4137
const onCopyText = (e: MouseEvent) => {
@@ -52,16 +48,52 @@ function main() {
5248
}, 3000)
5349
}
5450

51+
const divider = createDivider()
5552
const textExport = createMenuItem(iconCopy, 'Copy Text', onCopyText)
5653
const pngExport = createMenuItem(iconCamera, 'Screenshot', exportToPng)
5754
const htmlExport = createMenuItem(fileCode, 'Export WebPage', exportToHtml)
58-
firstMenuItem.after(divider, textExport, pngExport, htmlExport)
55+
const container = createMenuContainer()
56+
container.append(textExport, pngExport, htmlExport, divider)
5957
})
6058
}
6159

60+
function createMenuContainer() {
61+
const container = document.createElement('div')
62+
container.id = 'exporter-menu'
63+
container.className = 'pt-1'
64+
65+
const chatList = document.querySelector('nav > div')
66+
if (chatList) {
67+
chatList.after(container)
68+
sentinel.on('nav > div.overflow-y-auto', (el) => {
69+
const nav = document.querySelector('nav')!
70+
if (container.parentElement !== nav) {
71+
el.after(container)
72+
}
73+
})
74+
}
75+
else {
76+
const nav = document.querySelector('nav')!
77+
nav.append(container)
78+
sentinel.on('nav', (el) => {
79+
if (container.parentElement !== nav) {
80+
el.append(container)
81+
}
82+
})
83+
}
84+
85+
return container
86+
}
87+
88+
function createDivider() {
89+
const divider = document.createElement('div')
90+
divider.className = 'border-b border-white/20'
91+
return divider
92+
}
93+
6294
function createMenuItem(icon: string, title: string, onClick: (e: MouseEvent) => void) {
63-
const firstMenuItem = document.querySelector('nav > a')!
64-
const menuItem = firstMenuItem.cloneNode(true) as HTMLAnchorElement
95+
const menuItem = document.createElement('a')
96+
menuItem.className = 'flex py-3 px-3 items-center gap-3 rounded-md hover:bg-gray-500/10 transition-colors duration-200 text-white cursor-pointer text-sm mb-2 flex-shrink-0 border border-white/20'
6597
menuItem.removeAttribute('href')
6698
menuItem.innerHTML = `${icon}${title}`
6799
menuItem.addEventListener('click', onClick)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
declare module 'sentinel-js' {
2+
export function on<T = HTMLElement>(cssSelectors: string | string[], callback: (el: T) => void): void
3+
export function off<T = HTMLElement>(event: string | string[], callback: (el: T) => void): void
4+
export function reset(): void
5+
}

0 commit comments

Comments
 (0)