Skip to content

Commit 224ce83

Browse files
committed
feat: add footer component with social links
feat: implement image viewer module for zoom functionality feat: create content script entry point for WeChat articles feat: add linkifier module to convert plain text URLs to clickable links feat: implement scroll observer for synchronizing table of contents with scroll position feat: develop table of contents generation logic feat: create UI rendering module for table of contents feat: add up-to-top button functionality fix: update storage utility to save and retrieve article content fix: add injected script for link hover effects fix: update permissions and web accessible resources in config
1 parent d1cbfa8 commit 224ce83

21 files changed

Lines changed: 215 additions & 8 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## [v2.0.6] - 2025-06-08
2+
3+
### ✨ 新特性
4+
5+
- **去AI 检测**:支持点击标题右侧按钮跳转朱雀大模型检测
6+
- **返回顶部**:右下角增加返回顶部按钮
17
## [v2.0.5] - 2025-05-26
28

39
### ✨ 新特性

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "wechat-reader-enhancer",
33
"type": "module",
4-
"version": "2.0.5",
4+
"version": "2.0.6",
55
"private": true,
66
"description": "为微信公众号文章生成结构化目录,提升阅读体验",
77
"scripts": {

public/injected.css

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,18 @@ body.wx_wap_page.wre-serif-fonts {
99
body.wx_wap_page.text-justify p {
1010
text-align: justify;
1111
}
12+
13+
.wechat-toc-ai-detect-button {
14+
font-size: 0.5em;
15+
padding: 0.2em 0.6em;
16+
border: none;
17+
border-radius: 4px;
18+
background-color: #07c160;
19+
color: white;
20+
cursor: pointer;
21+
transition: background-color 0.3s;
22+
}
23+
24+
.wechat-toc-ai-detect-button:hover {
25+
background-color: #06a950;
26+
}

src/ai-detect.content/App.vue

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<script lang="ts" setup>
2+
import { onMounted } from 'vue'
3+
import { getArticleContent, watchArticleContent } from '../utils/storage'
4+
5+
const unwatch = watchArticleContent((newContent, _oldContent) => {
6+
if (newContent) {
7+
const container = document.querySelector(`.txt-input textarea`)
8+
if (container) {
9+
container.value = newContent
10+
container.dispatchEvent(new Event(`input`)) // Trigger input event to update any bindings
11+
}
12+
}
13+
})
14+
onMounted(async () => {
15+
console.log(`AI Detect Content Script Loaded`)
16+
const content = await getArticleContent()
17+
const container = document.querySelector(`.txt-input textarea`)
18+
if (content && container) {
19+
container.value = content
20+
container.dispatchEvent(new Event(`input`)) // Trigger input event to update any bindings
21+
}
22+
})
23+
onUnmounted(() => {
24+
unwatch()
25+
})
26+
</script>
27+
28+
<template>
29+
<div />
30+
</template>

src/ai-detect.content/index.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// https://matrix.tencent.com/ai-detect/
2+
// 1. Import the style
3+
import { createApp } from 'vue'
4+
import App from './App.vue'
5+
6+
export default defineContentScript({
7+
matches: [`https://matrix.tencent.com/ai-detect/`],
8+
// 2. Set cssInjectionMode
9+
cssInjectionMode: `manual`,
10+
11+
async main(ctx) {
12+
// 3. Define your UI
13+
const ui = await createShadowRootUi(ctx, {
14+
name: `we-toc-ui`,
15+
position: `inline`,
16+
anchor: `body`,
17+
onMount: (container) => {
18+
// Define how your UI will be mounted inside the container
19+
const app = createApp(App)
20+
app.mount(container)
21+
return app
22+
},
23+
onRemove: (app) => {
24+
// Unmount the app when the UI is removed
25+
app?.unmount()
26+
},
27+
})
28+
29+
// 4. Mount the UI
30+
ui.mount()
31+
},
32+
})

src/background/ai-detect.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { browser } from '#imports'
2+
3+
const targetUrl = `https://matrix.tencent.com/ai-detect/`
4+
5+
export async function openAiDetectPage() {
6+
try {
7+
const tabs = await browser.tabs.query({ url: targetUrl })
8+
if (tabs && tabs.length > 0) {
9+
const tab = tabs[0]
10+
await browser.tabs.update(tab.id!, { active: true })
11+
await browser.windows.update(tab.windowId, { focused: true })
12+
}
13+
else {
14+
await browser.tabs.create({ url: targetUrl })
15+
}
16+
}
17+
catch (error) {
18+
console.error(`Error querying tabs:`, error)
19+
}
20+
}

src/background/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type { Requests } from '../types'
77
import { defaultSettings } from '../composable/config'
88
import { MessageType } from '../types'
99
import { chat } from './agent'
10+
import { openAiDetectPage } from './ai-detect'
1011

1112
export default defineBackground(() => {
1213
console.log(`公众号阅读增强插件背景服务工作进程已启动`, { id: browser.runtime.id })
@@ -28,6 +29,10 @@ export default defineBackground(() => {
2829
if (message.type === MessageType.GET_SUMMARY) {
2930
return chat(message.data)
3031
}
32+
if (message.type === MessageType.OPEN_AI_DETECT) {
33+
return openAiDetectPage()
34+
}
35+
console.warn(`未知消息类型`, message.type)
3136
return true
3237
})
3338
})

src/composable/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export function useSettings(handleSettingsChange: (settings: Settings) => void)
3434
onMounted(async () => {
3535
console.log(`useSettings mounted`)
3636
const item = await storage.getItem<Settings>(`sync:settings`)
37-
console.log(`useSettings getItem`, item)
37+
// console.log(`useSettings getItem`, item)
3838
if (item) {
3939
settings.value = item
4040
}
Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script setup lang="tsx">
22
import type { ChatCompletionResponse, Settings, TocItem } from '../types'
3+
import { injectScript } from '#imports'
34
import { marked } from 'marked'
45
import QRCode from 'qrcode'
56
import readingTime from 'reading-time/lib/reading-time'
@@ -8,7 +9,7 @@ import { useSettings } from '../composable/config'
89
import { useScanImages } from '../composable/scan'
910
import { MessageType } from '../types'
1011
import { addClass, createElement, findHeadings, removeClass, scrollToElement, toggleClass } from '../utils/dom'
11-
import { getReadingPosition } from '../utils/storage'
12+
import { getReadingPosition, saveArticleContent } from '../utils/storage'
1213
import { transformHtml2Markdown } from '../utils/turndown'
1314
import Footer from './Footer.vue'
1415
import { destroyImageViewer, initImageViewer } from './imageViewer'
@@ -101,6 +102,40 @@ function handleJustifyText() {
101102
removeClass(document.body, `text-justify`)
102103
}
103104
}
105+
function addAIDectectButton() {
106+
const container = document.querySelector(`#activity-name`)
107+
if (container) {
108+
const span = document.createElement(`span`)
109+
span.className = `wechat-toc-ai-detect-button`
110+
span.textContent = `去AI检测`
111+
container.appendChild(span)
112+
span.addEventListener(`click`, async () => {
113+
// 将文章以纯文本的方式写入到 storage 中
114+
const original = document.querySelector(`#js_content`)
115+
if (original) {
116+
const clone = original.cloneNode(true) // 深拷贝
117+
const toRemove = clone.querySelector(`.wechat-toc-summary-container`)
118+
if (toRemove) {
119+
toRemove.remove()
120+
}
121+
const filteredText = clone.textContent
122+
saveArticleContent(filteredText || ``)
123+
browser.runtime.sendMessage({
124+
type: MessageType.OPEN_AI_DETECT,
125+
}).then(() => {
126+
console.log(`AI检测按钮点击,已发送消息`)
127+
}).catch((error) => {
128+
console.error(`AI检测按钮点击失败:`, error)
129+
})
130+
}
131+
})
132+
}
133+
}
134+
async function addUpToTopButton() {
135+
await injectScript(`/up-to-top.js`, {
136+
keepInDom: true,
137+
})
138+
}
104139
useScanImages()
105140
/**
106141
* 初始化插件
@@ -117,13 +152,20 @@ async function init() {
117152
// 初始化滚动监听
118153
initScrollObserver(toRaw(itemList.value))
119154
120-
// addVerticalText()
155+
// http/https 文本转超链接
121156
initLinkifier()
157+
await injectScript(`/wechat-linkifier-injected.js`, {
158+
keepInDom: true,
159+
})
122160
123161
// 是否使用衬线字体
124162
handleSeriFont()
125163
// 是否使用文本对齐
126164
handleJustifyText()
165+
// 去AI 检测
166+
addAIDectectButton()
167+
// 返回顶部
168+
addUpToTopButton()
127169
console.log(`公众号阅读增强插件初始化完成`)
128170
}
129171
catch (error) {

0 commit comments

Comments
 (0)