Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 03e36ccb93 |
@@ -19,8 +19,6 @@ yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
pnpm-lock.yaml
|
||||
|
||||
# local env files
|
||||
.env*.local
|
||||
|
||||
@@ -37,7 +35,5 @@ dist/
|
||||
|
||||
.idea
|
||||
.vscode
|
||||
|
||||
pnpm-lock.yaml
|
||||
.env
|
||||
|
||||
server
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
# codebox-一键复制代码/下载文章
|
||||
## codebox-一键复制代码/下载文章
|
||||
|
||||
[中文](README.md) | [English](README_EN.md)
|
||||
## 代码
|
||||
|
||||
## 网站
|
||||
1. 官网
|
||||
https://www.code-box.fun/
|
||||
2. 文档
|
||||
https://code-box.fun/docs
|
||||
https://github.com/027xiguapi/code-box
|
||||
|
||||
## 介绍
|
||||
|
||||
@@ -18,10 +14,10 @@ https://code-box.fun/docs
|
||||
|
||||
直接下载安装:
|
||||
1. 进入应用商店
|
||||
- [Chrome应用商店](https://chrome.google.com/webstore/category/extensions?hl=zh-CN)
|
||||
- [Edge应用商店](https://microsoftedge.microsoft.com/addons/Microsoft-Edge-Extensions-Home?hl=zh-CN)
|
||||
- [Chrome网上应用商店](https://chrome.google.com/webstore/category/extensions?hl=zh-CN)
|
||||
- [Edge网上应用商店](https://microsoftedge.microsoft.com/addons/Microsoft-Edge-Extensions-Home?hl=zh-CN)
|
||||
- [360浏览器应用商店](https://ext.se.360.cn/#/extension-detail?id=acnnhjllgegbndgknlliobjlekgilbdf)
|
||||
- [Firefox应用商店](https://addons.mozilla.org/zh-CN/firefox/)
|
||||
- [Firefox网上应用商店](https://addons.mozilla.org/zh-CN/firefox/)
|
||||
|
||||
2. 搜索:`codebox`
|
||||
|
||||
@@ -40,7 +36,7 @@ https://code-box.fun/docs
|
||||
### 安装方式三:公众号下载
|
||||
1. 关注公众号
|
||||
|
||||

|
||||

|
||||
|
||||
2. 点击 `软件下载`
|
||||
|
||||
@@ -71,28 +67,13 @@ https://code-box.fun/docs
|
||||
### 自定义
|
||||
|
||||
- 插入自定义样式(css代码)
|
||||
- 下载所有图片
|
||||
- 自定义选择下载html
|
||||
- 自定义选择下载markdown
|
||||
- 自定义选择下载pdf
|
||||
|
||||
|
||||
### 微信
|
||||
- 插入自定义样式(css代码)
|
||||
- 一键下载文章html
|
||||
- 一键下载文章markdown
|
||||
- 一键下载文章pdf
|
||||
- 一键下载所有图片
|
||||
|
||||
### 掘金
|
||||
- 插入自定义样式(css代码)
|
||||
- 一键下载文章html
|
||||
- 一键下载文章markdown
|
||||
- 一键下载文章pdf
|
||||
|
||||
### CSDN
|
||||
|
||||
- 一键下载文章html、pdf或markdown文件
|
||||
- 一键下载文章html或markdown文件
|
||||
- 打开任意一个`CSDN`博客即可开始复制代码
|
||||
- 未登录`CSDN`状态下,支持选中代码
|
||||
- 未登录`CSDN`状态下,代码右上角按钮一键复制
|
||||
@@ -101,61 +82,54 @@ https://code-box.fun/docs
|
||||
- 自动展开代码块
|
||||
- 移动端屏蔽跳转APP
|
||||
- 非vip用户,不再提示vip观看,且完整展示文章
|
||||
- 插入自定义样式(css代码)
|
||||
|
||||
### 知乎
|
||||
|
||||
- 一键下载文章html、pdf或markdown文件
|
||||
- 一键下载文章html或markdown文件
|
||||
- 一键复制代码
|
||||
- 未登录`知乎`状态下,不再提示展开阅读全文,且完整展示文章
|
||||
- 未登录`知乎`状态下,不会再出现强制登录弹窗
|
||||
- 插入自定义样式(css代码)
|
||||
|
||||
### 百度
|
||||
|
||||
- 一键下载对话框html、pdf或markdown文件
|
||||
- 一键下载对话框html或markdown文件
|
||||
- 关闭AI对话框
|
||||
|
||||
### 简书
|
||||
|
||||
- 一键下载文章html、pdf或markdown文件
|
||||
- 一键下载文章html或markdown文件
|
||||
- 移动端,一键复制代码
|
||||
- 不再提示展开阅读全文,且完整展示文章
|
||||
- 不会再出现强制登录弹窗
|
||||
- 插入自定义样式(css代码)
|
||||
|
||||
### 脚本之家
|
||||
|
||||
- 一键下载文章html、pdf或markdown文件
|
||||
- 一键下载文章html或markdown文件
|
||||
- 打开任意一个`脚本之家`博客即可开始复制代码
|
||||
- 未登录`脚本之家`状态下,支持选中代码
|
||||
- 屏蔽广告
|
||||
- 移动端未登录`脚本之家`状态下,代码右上角按钮一键复制
|
||||
- 插入自定义样式(css代码)
|
||||
|
||||
### 博客园
|
||||
|
||||
- 一键下载文章html、pdf或markdown文件
|
||||
- 一键下载文章html或markdown文件
|
||||
- 一键复制代码
|
||||
- 插入自定义样式(css代码)
|
||||
|
||||
### 51CTO博客
|
||||
|
||||
- 一键下载文章html、pdf或markdown文件
|
||||
- 一键下载文章html或markdown文件
|
||||
- 未登录`51CTO博客`状态下,支持选中代码
|
||||
- 未登录`51CTO博客`状态下,代码右上角按钮一键复制
|
||||
- 未登录`51CTO博客`状态下,不会再出现强制登录弹窗
|
||||
- 移动端未登录`51CTO博客`状态下,代码右上角按钮一键复制
|
||||
- 插入自定义样式(css代码)
|
||||
|
||||
### php中文网
|
||||
|
||||
- 一键下载文章html、pdf或markdown文件
|
||||
- 一键下载文章html或markdown文件
|
||||
- 未登录`php中文网`状态下,支持选中代码
|
||||
- 未登录`php中文网`状态下,代码右上角按钮一键复制
|
||||
- 未登录`php中文网`状态下,不会再出现强制登录弹窗
|
||||
- 未登录`php中文网`状态下,移动端代码右上角按钮一键复制
|
||||
- 插入自定义样式(css代码)
|
||||
|
||||

|
||||

|
||||
@@ -175,14 +149,11 @@ https://code-box.fun/docs
|
||||
3. [Chrome 应用商店一站式支持](https://support.google.com/chrome_webstore/contact/one_stop_support)
|
||||
4. [开箱即用的web打印和下载](https://juejin.cn/post/7412672713376497727)
|
||||
5. [导出微信公众号文章为PDF](https://greasyfork.org/en/scripts/510683-%E5%AF%BC%E5%87%BA%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7%E6%96%87%E7%AB%A0%E4%B8%BApdf/code)
|
||||
6. [微信公众号推文图片一键下载](https://greasyfork.org/zh-CN/scripts/40583-%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7%E6%8E%A8%E6%96%87%E5%9B%BE%E7%89%87%E4%B8%80%E9%94%AE%E4%B8%8B%E8%BD%BD/code)
|
||||
|
||||
## 隐私政策
|
||||
|
||||
[网页](https://027xiguapi.github.io/code-box/privacy-policy.html)
|
||||
|
||||
## 联系
|
||||
## 支持
|
||||
|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
@@ -1,184 +0,0 @@
|
||||
# Codebox - One-click Code Copying/Downloading Articles
|
||||
|
||||
[中文](README.md) | [English](README_EN.md)
|
||||
|
||||
## official website
|
||||
|
||||
https://www.code-box.fun/
|
||||
|
||||
## Introduction
|
||||
|
||||
This browser plugin can be used on websites like CSDN/Zhihu/Script Home/Blog Garden/51CTO Blog/PHP Chinese Network/Juejin/WeChat, etc., to download articles as HTML or Markdown files with one click; to copy code without logging in; to support selected code; or to copy code with one click from the button in the upper right corner of the code; to remove the prompt to follow the blogger to read the full text; to remove the login pop-up window; to remove the pop-up window to jump to the APP.
|
||||
|
||||
## Installation
|
||||
|
||||
### Installation Method 1: Plugin Store (Recommended)
|
||||
|
||||
Directly download and install:
|
||||
1. Enter the app store
|
||||
- [Chrome Web Store](https://chrome.google.com/webstore/category/extensions?hl=zh-CN)
|
||||
- [Edge Web Store](https://microsoftedge.microsoft.com/addons/Microsoft-Edge-Extensions-Home?hl=zh-CN)
|
||||
- [360 Browser App Store](https://ext.se.360.cn/#/extension-detail?id=acnnhjllgegbndgknlliobjlekgilbdf)
|
||||
- [Firefox Web Store](https://addons.mozilla.org/zh-CN/firefox/)
|
||||
|
||||
2. Search: `codebox`
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
### Installation Method 2: Direct Installation
|
||||
|
||||
1. Installation address:
|
||||
- [Go to Chrome Extension Store](https://chrome.google.com/webstore/detail/acnnhjllgegbndgknlliobjlekgilbdf)
|
||||
- [Go to 360 Browser Extension Store](https://ext.se.360.cn/#/extension-detail?id=acnnhjllgegbndgknlliobjlekgilbdf)
|
||||
- [Go to Firefox Extension Store](https://addons.mozilla.org/zh-CN/firefox/addon/code-box/)
|
||||
- [Go to Edge Extension Store](https://microsoftedge.microsoft.com/addons/detail/code-box/cfpdbfmncaampihkmejogihjkenkonbn)
|
||||
|
||||
### Installation Method 3: Download from WeChat Official Account
|
||||
|
||||
1. Follow the WeChat official account
|
||||
|
||||

|
||||
|
||||
2. Click `Software Download`
|
||||
|
||||

|
||||
|
||||
### Installation Method 4: Source Code Installation
|
||||
|
||||
1. Clone the source code
|
||||
```sh
|
||||
git clone https://github.com/027xiguapi/code-box.git
|
||||
```
|
||||
2. Install and package
|
||||
```sh
|
||||
pnpm install
|
||||
pnpm dev
|
||||
pnpm build
|
||||
```
|
||||
3. For Google Chrome, you can enter the plugin management page from the upper right menu -> More tools -> Extensions, or you can directly enter chrome://extensions in the address bar to access it.
|
||||
4. Check the developer mode, and you can directly load the plugin in the form of a folder.
|
||||
|
||||
## Function
|
||||
|
||||

|
||||
|
||||
### Customization
|
||||
|
||||
- Insert custom styles (CSS code)
|
||||
- Download all images
|
||||
- Customize the selection to download HTML
|
||||
- Customize the selection to download Markdown
|
||||
- Customize the selection to download PDF
|
||||
|
||||
### WeChat
|
||||
|
||||
- Insert custom styles (CSS code)
|
||||
- One-click download of article HTML
|
||||
- One-click download of article Markdown
|
||||
- One-click download of article PDF
|
||||
- One-click download of all images
|
||||
|
||||
### Nuggets
|
||||
|
||||
- Insert custom styles (CSS code)
|
||||
- One-click download of article HTML
|
||||
- One-click download of article Markdown
|
||||
- One-click download of article PDF
|
||||
|
||||
### CSDN
|
||||
|
||||
- One-click download of article HTML, PDF, or Markdown files
|
||||
- Open any `CSDN` blog to start copying code
|
||||
- Support for selected code when not logged in to `CSDN`
|
||||
- One-click copy of code from the button in the upper right corner of the code when not logged in to `CSDN`
|
||||
- No more forced login pop-ups when not logged in to `CSDN`
|
||||
- No more prompts to follow the blogger to read the full text when not following the blogger, and the full text is displayed
|
||||
- Automatically expand code blocks
|
||||
- Block APP redirection on mobile
|
||||
- For non-VIP users, no more prompts for VIP viewing, and the full text is displayed
|
||||
- Insert custom styles (CSS code)
|
||||
|
||||
### Zhihu
|
||||
|
||||
- One-click download of article HTML, PDF, or Markdown files
|
||||
- One-click copy of code
|
||||
- No more prompts to expand and read the full text when not logged in to `Zhihu`, and the full text is displayed
|
||||
- No more forced login pop-ups when not logged in to `Zhihu`
|
||||
- Insert custom styles (CSS code)
|
||||
|
||||
### Baidu
|
||||
|
||||
- One-click download of dialog box HTML, PDF, or Markdown files
|
||||
- Close AI dialog box
|
||||
|
||||
### Jian Shu
|
||||
|
||||
- One-click download of article HTML, PDF, or Markdown files
|
||||
- One-click copy of code on mobile
|
||||
- No more prompts to expand and read the full text, and the full text is displayed
|
||||
- No more forced login pop-ups
|
||||
- Insert custom styles (CSS code)
|
||||
|
||||
### Script Home
|
||||
|
||||
- One-click download of article HTML, PDF, or Markdown files
|
||||
- Open any `Script Home` blog to start copying code
|
||||
- Support for selected code when not logged in to `Script Home`
|
||||
- Block ads
|
||||
- One-click copy of code from the button in the upper right corner of the code on mobile when not logged in to `Script Home`
|
||||
- Insert custom styles (CSS code)
|
||||
|
||||
### Blog Garden
|
||||
|
||||
- One-click download of article HTML, PDF, or Markdown files
|
||||
- One-click copy of code
|
||||
- Insert custom styles (CSS code)
|
||||
|
||||
### 51CTO Blog
|
||||
|
||||
- One-click download of article HTML, PDF, or Markdown files
|
||||
- Support for selected code when not logged in to `51CTO Blog`
|
||||
- One-click copy of code from the button in the upper right corner of the code when not logged in to `51CTO Blog`
|
||||
- No more forced login pop-ups when not logged in to `51CTO Blog`
|
||||
- One-click copy of code from the button in the upper right corner of the code on mobile when not logged in to `51CTO Blog`
|
||||
- Insert custom styles (CSS code)
|
||||
|
||||
### PHP Chinese Network
|
||||
|
||||
- One-click download of article HTML, PDF, or Markdown files
|
||||
- Support for selected code when not logged in to `PHP Chinese Network`
|
||||
- One-click copy of code from the button in the upper right corner of the code when not logged in to `PHP Chinese Network`
|
||||
- No more forced login pop-ups when not logged in to `PHP Chinese Network`
|
||||
- One-click copy of code from the button in the upper right corner of the code on mobile when not logged in to `PHP Chinese Network`
|
||||
- Insert custom styles (CSS code)
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
## Reference
|
||||
|
||||
1. [copy-csdn](https://github.com/openHacking/copy-csdn)
|
||||
2. [plasmo](https://github.com/PlasmoHQ/plasmo)
|
||||
3. [Chrome App Store One-stop Support](https://support.google.com/chrome_webstore/contact/one_stop_support)
|
||||
4. [Out-of-the-box web printing and downloading](https://juejin.cn/post/7412672713376497727)
|
||||
5. [Export WeChat Official Account Articles to PDF](https://greasyfork.org/en/scripts/510683-%E5%AF%BC%E5%87%BA%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7%E6%96%87%E7%AB%A0%E4%B8%BApdf/code)
|
||||
6. [One-click Download of WeChat Official Account Article Images](https://greasyfork.org/zh-CN/scripts/40583-%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7%E6%8E%A8%E6%96%87%E5%9B%BE%E7%89%87%E4%B8%80%E9%94%AE%E4%B8%8B%E8%BD%BD/code)
|
||||
|
||||
## Privacy Policy
|
||||
|
||||
[Webpage](https://027xiguapi.github.io/code-box/privacy-policy.html)
|
||||
|
||||
## Support
|
||||
|
||||

|
||||
|
||||

|
||||
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 9.1 KiB |
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 5.6 KiB |
@@ -13,14 +13,42 @@ chrome.runtime.onInstalled.addListener(function (object) {
|
||||
chrome.runtime.requestUpdateCheck(function (status, details) {
|
||||
if (status === "update_available") {
|
||||
console.log("有更新可用!版本" + details.version)
|
||||
// chrome.action.setBadgeBackgroundColor({ color: "#fc5430" })
|
||||
// chrome.action.setBadgeText({
|
||||
// text: "升级"
|
||||
// })
|
||||
// chrome.runtime.reload()
|
||||
chrome.action.setBadgeBackgroundColor({ color: "#fc5430" })
|
||||
chrome.action.setBadgeText({
|
||||
text: "升级"
|
||||
})
|
||||
chrome.runtime.reload()
|
||||
} else if (status === "no_update") {
|
||||
console.log("没有可用更新。")
|
||||
} else if (status === "throttled") {
|
||||
console.log("更新检查被限流。")
|
||||
}
|
||||
})
|
||||
|
||||
chrome.tabs.onUpdated.addListener((tabId, _, tab) => {
|
||||
// console.log(tabId, _, tab)
|
||||
// if (!("sidePanel" in chrome)) {
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// void (async () => {
|
||||
// if (!tab.url) {
|
||||
// return
|
||||
// }
|
||||
// // const url = new URL(tab.url)
|
||||
// // if (
|
||||
// // url.origin === ""
|
||||
// // ) {
|
||||
// // await chrome.sidePanel.setOptions({
|
||||
// // tabId,
|
||||
// // // path: "pages/options.html",
|
||||
// // enabled: true
|
||||
// // })
|
||||
// // } else {
|
||||
// // await chrome.sidePanel.setOptions({
|
||||
// // tabId,
|
||||
// // enabled: false
|
||||
// // })
|
||||
// // }
|
||||
// })()
|
||||
})
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
import JSZip from "jszip"
|
||||
|
||||
import type { PlasmoMessaging } from "@plasmohq/messaging"
|
||||
|
||||
const handler: PlasmoMessaging.MessageHandler = async (req, res) => {
|
||||
const { imageUrls, title, action, onProgress } = req.body
|
||||
if (action === "downloadAllImages") {
|
||||
const zip = new JSZip()
|
||||
|
||||
const fetchImage = (url) => {
|
||||
return fetch(url)
|
||||
.then((response) => response.blob())
|
||||
.then((blob) => {
|
||||
const fileName = url.split("/").pop().split("?")[0]
|
||||
return { blob, fileName }
|
||||
})
|
||||
}
|
||||
|
||||
Promise.all(imageUrls.map(fetchImage))
|
||||
.then((results) => {
|
||||
results.forEach(({ blob, fileName }, index) => {
|
||||
onProgress && onProgress(index + 1, imageUrls.length)
|
||||
zip.file(fileName || `image-${index}.jpg`, blob)
|
||||
})
|
||||
|
||||
return zip.generateAsync({ type: "blob" })
|
||||
})
|
||||
.then((zipBlob) => {
|
||||
const reader = new FileReader()
|
||||
reader.onload = function (event) {
|
||||
const dataUrl = event.target.result as string
|
||||
|
||||
chrome.downloads.download(
|
||||
{
|
||||
url: dataUrl,
|
||||
filename: `${title}.zip`
|
||||
},
|
||||
() => {
|
||||
res.send({ code: 200, msg: "success" })
|
||||
}
|
||||
)
|
||||
}
|
||||
reader.readAsDataURL(zipBlob)
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
res.send({ code: 0, msg: err })
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default handler
|
||||
@@ -1,17 +1,9 @@
|
||||
import { type PlasmoMessaging } from "@plasmohq/messaging"
|
||||
import type { PlasmoMessaging } from "@plasmohq/messaging"
|
||||
|
||||
const handler: PlasmoMessaging.MessageHandler = async (req, res) => {
|
||||
try {
|
||||
chrome.tabs.query({ active: true, currentWindow: true }, ([tab]) => {
|
||||
const { active } = req.body
|
||||
|
||||
if (active) {
|
||||
chrome.sidePanel.open({ tabId: tab.id })
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error("Error toggling side panel:", error)
|
||||
}
|
||||
const handler: PlasmoMessaging.MessageHandler = (req, res) => {
|
||||
chrome.tabs.query({ active: true, currentWindow: true }, ([tab]) => {
|
||||
chrome.sidePanel.open({ tabId: tab.id })
|
||||
})
|
||||
}
|
||||
|
||||
export default handler
|
||||
|
||||
@@ -1,57 +1,37 @@
|
||||
import { CheckOutlined, CloseOutlined } from "@ant-design/icons"
|
||||
import { KeyOutlined } from "@ant-design/icons"
|
||||
import { Button, Input, Space } from "antd"
|
||||
import dayjs from "dayjs"
|
||||
import qrcodeUrl from "raw:~/public/wx/gzh.jpg"
|
||||
import React, { useRef, useState } from "react"
|
||||
import qrcodeUrl from "raw:~/public/wx/qrcode_wx.jpg"
|
||||
import { useRef, useState } from "react"
|
||||
|
||||
import { sendToBackground } from "@plasmohq/messaging"
|
||||
import { useStorage } from "@plasmohq/storage/dist/hook"
|
||||
|
||||
const validateContent = {
|
||||
blueButton: {
|
||||
backgroundColor: "#1677FF",
|
||||
border: "1px solid #1677FF",
|
||||
color: "#fff",
|
||||
borderRadius: "4px",
|
||||
padding: "7px 15px",
|
||||
fontSize: "14px"
|
||||
},
|
||||
redButton: {
|
||||
backgroundColor: "#d9363e",
|
||||
border: "1px solid #d9363e",
|
||||
color: "#fff",
|
||||
borderRadius: "4px",
|
||||
padding: "7px 15px",
|
||||
fontSize: "14px"
|
||||
}
|
||||
}
|
||||
import { verifyTOTP } from "~utils/2FA"
|
||||
|
||||
export default function ValidateContent(props) {
|
||||
const [validTime, setValidTime] = useStorage("app-validTime", "1730390400")
|
||||
const [activationCode, setActivationCode] = useState("")
|
||||
const [isValid, setIsValid] = useState(true)
|
||||
|
||||
const handleChange = (event) => {
|
||||
const code = event.target.value
|
||||
setActivationCode(code)
|
||||
}
|
||||
const [isValid, setIsValid] = useState(false)
|
||||
const inputRef = useRef(null)
|
||||
|
||||
function handleSubmit() {
|
||||
if (Number(validTime) > dayjs().unix()) {
|
||||
props.handleOk()
|
||||
} else if (process.env.PLASMO_PUBLIC_CODEBOX_SECRET3 == activationCode) {
|
||||
let code = inputRef.current.input.value
|
||||
|
||||
if (verifyTOTP(process.env.PLASMO_PUBLIC_CODEBOX_SECRET1, code)) {
|
||||
let time = dayjs().add(20, "day").unix()
|
||||
setValidTime(String(time))
|
||||
setIsValid(true)
|
||||
} else if (verifyTOTP(process.env.PLASMO_PUBLIC_CODEBOX_SECRET2, code)) {
|
||||
let time = dayjs().add(65, "day").unix()
|
||||
setValidTime(String(time))
|
||||
setIsValid(true)
|
||||
} else if (process.env.PLASMO_PUBLIC_CODEBOX_SECRET3 == code) {
|
||||
let time = dayjs().add(7, "day").unix()
|
||||
setValidTime(String(time))
|
||||
setIsValid(true)
|
||||
props.handleOk()
|
||||
} else {
|
||||
setIsValid(false)
|
||||
}
|
||||
}
|
||||
|
||||
function handleCancel() {
|
||||
props.handleCancel()
|
||||
}
|
||||
|
||||
function help() {
|
||||
sendToBackground({
|
||||
name: "tab",
|
||||
@@ -61,98 +41,39 @@ export default function ValidateContent(props) {
|
||||
})
|
||||
}
|
||||
|
||||
const typeMap = {
|
||||
downloadHtml: "下载HTML",
|
||||
downloadMarkdown: "下载markdown",
|
||||
editMarkdown: "编辑markdown",
|
||||
parseMarkdown: "解析markdown",
|
||||
downloadPdf: "下载PDF"
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: "350px",
|
||||
padding: "10px",
|
||||
position: "absolute",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
backgroundColor: "white",
|
||||
borderRadius: "5px",
|
||||
textAlign: "center"
|
||||
}}>
|
||||
{Number(validTime) > dayjs().unix() ? (
|
||||
<>
|
||||
{isValid ? (
|
||||
<p className="valid" style={{ fontSize: "16px", color: "red" }}>
|
||||
已激活!确认{typeMap[props.type]}?
|
||||
验证成功
|
||||
</p>
|
||||
) : (
|
||||
<>
|
||||
<div style={{ fontSize: "14px", color: "red" }}>
|
||||
此功能需要关注公众号
|
||||
<p>
|
||||
【codebox代码助手】获取验证码(
|
||||
<a onClick={help} target="_blank">
|
||||
帮助
|
||||
</a>
|
||||
)
|
||||
</p>
|
||||
此功能需要关注公众号【codebox代码助手】获取验证码(
|
||||
<a onClick={help} target="_blank">
|
||||
帮助
|
||||
</a>
|
||||
)
|
||||
</div>
|
||||
<div>
|
||||
<img style={{ margin: "auto" }} src={qrcodeUrl} alt="微信公众号" />
|
||||
<img src={qrcodeUrl} alt="微信公众号" />
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
marginTop: "10px",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center"
|
||||
}}>
|
||||
<label
|
||||
htmlFor="activationCodeInput"
|
||||
style={{ display: "block", marginRight: "7px" }}>
|
||||
验证码:
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="activationCodeInput"
|
||||
value={activationCode}
|
||||
onChange={handleChange}
|
||||
style={{
|
||||
padding: "8px",
|
||||
borderRadius: "4px",
|
||||
border: isValid ? "1px solid #ccc" : "1px solid red",
|
||||
width: "200px",
|
||||
fontSize: "14px"
|
||||
}}
|
||||
placeholder="请输入验证码"
|
||||
<Space.Compact style={{ width: "100%" }}>
|
||||
<Input
|
||||
placeholder="输入激活码"
|
||||
ref={inputRef}
|
||||
prefix={<KeyOutlined />}
|
||||
/>
|
||||
</div>
|
||||
{!isValid ? (
|
||||
<div style={{ color: "red", fontSize: "14px", marginTop: "5px" }}>
|
||||
验证码错误
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
<Button
|
||||
type="primary"
|
||||
className="valid-submit"
|
||||
onClick={handleSubmit}>
|
||||
提交
|
||||
</Button>
|
||||
</Space.Compact>
|
||||
</>
|
||||
)}
|
||||
<div
|
||||
style={{
|
||||
margin: "10px 50px 0",
|
||||
display: "flex",
|
||||
justifyContent: "space-between"
|
||||
}}>
|
||||
<button
|
||||
className="valid-submit"
|
||||
style={validateContent.blueButton}
|
||||
onClick={handleSubmit}>
|
||||
<CheckOutlined /> 提交
|
||||
</button>
|
||||
<button style={validateContent.redButton} onClick={handleCancel}>
|
||||
<CloseOutlined /> 取消
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
import { DownloadOutlined, StarTwoTone } from "@ant-design/icons"
|
||||
import { useState } from "react"
|
||||
|
||||
import { sendToContentScript } from "@plasmohq/messaging"
|
||||
|
||||
import { i18n } from "~tools"
|
||||
|
||||
export default function DownloadImages({ name }) {
|
||||
const [isDownloading, setIsDownloading] = useState(false)
|
||||
const [progress, setProgress] = useState(0)
|
||||
|
||||
const handleDownload = async () => {
|
||||
if (isDownloading) return
|
||||
|
||||
try {
|
||||
setIsDownloading(true)
|
||||
setProgress(0)
|
||||
|
||||
const res = await sendToContentScript({
|
||||
name: `${name}-downloadImages`,
|
||||
body: {
|
||||
onProgress: (current, total) => {
|
||||
const percentage = Math.round((current / total) * 100)
|
||||
setProgress(percentage)
|
||||
}
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error("Failed to download images:", error)
|
||||
} finally {
|
||||
setIsDownloading(false)
|
||||
setProgress(0)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`item download ${isDownloading ? "downloading" : ""}`}
|
||||
onClick={handleDownload}
|
||||
style={{
|
||||
opacity: isDownloading ? 0.7 : 1,
|
||||
cursor: isDownloading ? "not-allowed" : "pointer"
|
||||
}}>
|
||||
<span>
|
||||
<StarTwoTone twoToneColor="#eb2f96" style={{ marginRight: "5px" }} />
|
||||
{isDownloading
|
||||
? `${i18n("downloading")} (${progress}%)`
|
||||
: i18n("downloadAllImg")}
|
||||
</span>
|
||||
<DownloadOutlined
|
||||
style={{
|
||||
color: isDownloading ? "#999" : "#52c41a",
|
||||
fontSize: "16px"
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
import CssCode from "~component/items/cssCode"
|
||||
import DownloadHtml from "~component/items/downloadHtml"
|
||||
import DownloadMarkdown from "~component/items/downloadMarkdown"
|
||||
import DownloadPdf from "~component/items/downloadPdf"
|
||||
import EditMarkdown from "~component/items/editMarkdown"
|
||||
import ShowTag from "~component/items/showTag"
|
||||
import { i18n } from "~tools"
|
||||
|
||||
export default function Options(props) {
|
||||
let { name } = props
|
||||
|
||||
return (
|
||||
<fieldset>
|
||||
<legend>{i18n(name + "Config")}</legend>
|
||||
<CssCode name={name}></CssCode>
|
||||
<ShowTag name={name}></ShowTag>
|
||||
<EditMarkdown name={name}></EditMarkdown>
|
||||
<DownloadMarkdown name={name}></DownloadMarkdown>
|
||||
<DownloadHtml name={name}></DownloadHtml>
|
||||
<DownloadPdf name={name}></DownloadPdf>
|
||||
</fieldset>
|
||||
)
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import { EditOutlined, StarTwoTone } from "@ant-design/icons"
|
||||
|
||||
import { sendToContentScript } from "@plasmohq/messaging"
|
||||
|
||||
import { i18n } from "~tools"
|
||||
|
||||
export default function ParseMarkdown(props) {
|
||||
let { name } = props
|
||||
|
||||
async function parseMarkdown() {
|
||||
sendToContentScript({
|
||||
name: `${name}-parseMarkdown`
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="item download" onClick={parseMarkdown}>
|
||||
<span>
|
||||
<StarTwoTone twoToneColor="#eb2f96" style={{ marginRight: "5px" }} />
|
||||
{i18n("parseMarkdown")}
|
||||
</span>
|
||||
<EditOutlined style={{ color: "#52c41a", fontSize: "16px" }} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import { EditOutlined, StarTwoTone } from "@ant-design/icons"
|
||||
|
||||
import { sendToContentScript } from "@plasmohq/messaging"
|
||||
import { useStorage } from "@plasmohq/storage/dist/hook"
|
||||
|
||||
import { i18n } from "~tools"
|
||||
|
||||
export default function SetAiType(props) {
|
||||
const [aiType, setAiType] = useStorage("app-aiType", (v) =>
|
||||
v === undefined ? "chatgpt" : v
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="item">
|
||||
<span>
|
||||
<StarTwoTone twoToneColor="#eb2f96" style={{ marginRight: "5px" }} />
|
||||
选择AI
|
||||
</span>
|
||||
<select
|
||||
name="custom-aiType"
|
||||
id="custom-aiType"
|
||||
value={aiType}
|
||||
onChange={(e) => setAiType(e.target.value)}>
|
||||
<option value="deepseek">deepseek</option>
|
||||
<option value="chatgpt">chatGPT</option>
|
||||
<option value="kimi">kimi</option>
|
||||
</select>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import Options from "~component/items/options"
|
||||
|
||||
export default function Doc360() {
|
||||
return <Options name="360doc" />
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import { useStorage } from "@plasmohq/storage/hook"
|
||||
import CssCode from "~component/items/cssCode"
|
||||
import DownloadHtml from "~component/items/downloadHtml"
|
||||
import DownloadMarkdown from "~component/items/downloadMarkdown"
|
||||
import DownloadPdf from "~component/items/downloadPdf"
|
||||
import EditMarkdown from "~component/items/editMarkdown"
|
||||
import ShowTag from "~component/items/showTag"
|
||||
import { i18n } from "~tools"
|
||||
@@ -62,7 +61,6 @@ export default function Cto51({ forwardRef }) {
|
||||
<EditMarkdown name="51cto"></EditMarkdown>
|
||||
<DownloadMarkdown name="51cto"></DownloadMarkdown>
|
||||
<DownloadHtml name="51cto"></DownloadHtml>
|
||||
<DownloadPdf name="51cto"></DownloadPdf>
|
||||
</fieldset>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,9 +5,7 @@ import { useStorage } from "@plasmohq/storage/hook"
|
||||
import CssCode from "~component/items/cssCode"
|
||||
import DownloadHtml from "~component/items/downloadHtml"
|
||||
import DownloadMarkdown from "~component/items/downloadMarkdown"
|
||||
import DownloadPdf from "~component/items/downloadPdf"
|
||||
import EditMarkdown from "~component/items/editMarkdown"
|
||||
import ShowTag from "~component/items/showTag"
|
||||
import { i18n } from "~tools"
|
||||
|
||||
export default function Baidu({ forwardRef }) {
|
||||
@@ -39,11 +37,9 @@ export default function Baidu({ forwardRef }) {
|
||||
<label className="codebox-switch" htmlFor="baidu-closeAIBox"></label>
|
||||
</div>
|
||||
<CssCode name="baidu"></CssCode>
|
||||
<ShowTag name="baidu"></ShowTag>
|
||||
<EditMarkdown name="baidu"></EditMarkdown>
|
||||
<DownloadMarkdown name="baidu"></DownloadMarkdown>
|
||||
<DownloadHtml name="baidu"></DownloadHtml>
|
||||
<DownloadPdf name="baidu"></DownloadPdf>
|
||||
</fieldset>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,9 +5,7 @@ import { useStorage } from "@plasmohq/storage/hook"
|
||||
import CssCode from "~component/items/cssCode"
|
||||
import DownloadHtml from "~component/items/downloadHtml"
|
||||
import DownloadMarkdown from "~component/items/downloadMarkdown"
|
||||
import DownloadPdf from "~component/items/downloadPdf"
|
||||
import EditMarkdown from "~component/items/editMarkdown"
|
||||
import ShowTag from "~component/items/showTag"
|
||||
import { i18n } from "~tools"
|
||||
|
||||
export default function Cnblogs({ forwardRef }) {
|
||||
@@ -39,12 +37,10 @@ export default function Cnblogs({ forwardRef }) {
|
||||
<label className="codebox-switch" htmlFor="cnblogs-copyCode"></label>
|
||||
</div>
|
||||
<CssCode name="cnblogs"></CssCode>
|
||||
<ShowTag name="cnblogs"></ShowTag>
|
||||
<EditMarkdown name="cnblogs"></EditMarkdown>
|
||||
<DownloadMarkdown name="cnblogs"></DownloadMarkdown>
|
||||
<DownloadHtml name="cnblogs"></DownloadHtml>
|
||||
<CssCode name="cnblogs"></CssCode>
|
||||
<DownloadPdf name="cnblogs"></DownloadPdf>
|
||||
</fieldset>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { BookOutlined, DownloadOutlined, StarTwoTone } from "@ant-design/icons"
|
||||
import { DownloadOutlined, StarTwoTone } from "@ant-design/icons"
|
||||
import { useImperativeHandle } from "react"
|
||||
|
||||
import { sendToBackground, sendToContentScript } from "@plasmohq/messaging"
|
||||
import { useStorage } from "@plasmohq/storage/hook"
|
||||
|
||||
import DownloadImages from "~component/items/downloadImages"
|
||||
import SetAiType from "~component/items/setAiType"
|
||||
import { i18n } from "~tools"
|
||||
|
||||
export default function Config({ forwardRef }) {
|
||||
@@ -15,28 +13,13 @@ export default function Config({ forwardRef }) {
|
||||
const [closeLog, setCloseLog] = useStorage("config-closeLog", (v) =>
|
||||
v === undefined ? true : v
|
||||
)
|
||||
const [allShowTag, setAllShowTag] = useStorage("config-allShowTag", (v) =>
|
||||
v === undefined ? true : v
|
||||
)
|
||||
|
||||
function downloadFullImg() {
|
||||
async function downloadImg() {
|
||||
sendToContentScript({
|
||||
name: "app-full-page-screenshot"
|
||||
})
|
||||
}
|
||||
|
||||
function getSummary() {
|
||||
sendToContentScript({
|
||||
name: "app-get-summary"
|
||||
})
|
||||
sendToBackground({
|
||||
name: "sidepanel",
|
||||
body: {
|
||||
active: true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function handleReset() {
|
||||
setCopyCode(true)
|
||||
setCloseLog(true)
|
||||
@@ -49,7 +32,6 @@ export default function Config({ forwardRef }) {
|
||||
return (
|
||||
<fieldset>
|
||||
<legend>{i18n("AppConfig")}</legend>
|
||||
<SetAiType />
|
||||
<div className="item">
|
||||
<span>{i18n("copyCode")}</span>
|
||||
<input
|
||||
@@ -62,18 +44,6 @@ export default function Config({ forwardRef }) {
|
||||
/>
|
||||
<label className="codebox-switch" htmlFor="config-copyCode"></label>
|
||||
</div>
|
||||
<div className="item">
|
||||
<span>{i18n("allShowTag")}</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="allShowTag"
|
||||
name="allShowTag"
|
||||
className="codebox-offscreen"
|
||||
checked={allShowTag}
|
||||
onChange={(e) => setAllShowTag(e.target.checked)}
|
||||
/>
|
||||
<label htmlFor="allShowTag" className="codebox-switch"></label>
|
||||
</div>
|
||||
<div className="item">
|
||||
<span>{i18n("configCloseLog")}</span>
|
||||
<input
|
||||
@@ -86,21 +56,13 @@ export default function Config({ forwardRef }) {
|
||||
/>
|
||||
<label className="codebox-switch" htmlFor="config-closeLog"></label>
|
||||
</div>
|
||||
<DownloadImages name="app"></DownloadImages>
|
||||
<div className="item download" onClick={downloadFullImg}>
|
||||
<div className="item download" onClick={downloadImg}>
|
||||
<span>
|
||||
<StarTwoTone twoToneColor="#eb2f96" style={{ marginRight: "5px" }} />
|
||||
{i18n("fullPageScreenshot")}
|
||||
</span>
|
||||
<DownloadOutlined style={{ color: "#52c41a", fontSize: "16px" }} />
|
||||
</div>
|
||||
<div className="item download" onClick={getSummary}>
|
||||
<span>
|
||||
<StarTwoTone twoToneColor="#eb2f96" style={{ marginRight: "5px" }} />
|
||||
总结文章
|
||||
</span>
|
||||
<BookOutlined style={{ color: "#52c41a", fontSize: "16px" }} />
|
||||
</div>
|
||||
</fieldset>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { useEffect, useRef, useState } from "react"
|
||||
import React, { useEffect, useState } from "react"
|
||||
|
||||
import Cto51 from "~component/options/51cto"
|
||||
import Doc360 from "~component/options/360doc"
|
||||
import Baidu from "~component/options/baidu"
|
||||
import Cnblogs from "~component/options/cnblogs"
|
||||
import Config from "~component/options/config"
|
||||
@@ -10,106 +9,69 @@ import Custom from "~component/options/custom"
|
||||
import Jb51 from "~component/options/jb51"
|
||||
import Jianshu from "~component/options/jianshu"
|
||||
import Juejin from "~component/options/juejin"
|
||||
import Lougu from "~component/options/lougu"
|
||||
import Medium from "~component/options/medium"
|
||||
import Mp from "~component/options/mp"
|
||||
import Oschina from "~component/options/oschina"
|
||||
import Paywallbuster from "~component/options/paywallbuster"
|
||||
import Php from "~component/options/php"
|
||||
import Pianshen from "~component/options/pianshen"
|
||||
import Segmentfault from "~component/options/segmentfault"
|
||||
import Weixin from "~component/options/weixin"
|
||||
import Zhihu from "~component/options/zhihu"
|
||||
|
||||
let csdnIsShow = false
|
||||
let zhihuIsShow = false
|
||||
let baiduIsShow = false
|
||||
let jianshuIsShow = false
|
||||
let jb51IsShow = false
|
||||
let cnblogsIsShow = false
|
||||
let ctoIsShow = false
|
||||
let juejinIsShow = false
|
||||
let phpIsShow = false
|
||||
let oschinaIsShow = false
|
||||
let segmentfaultIsShow = false
|
||||
let mediumIsShow = false
|
||||
let paywallbusterIsShow = false
|
||||
let doc360IsShow = false
|
||||
let mpIsShow = false
|
||||
let weixinIsShow = false
|
||||
let pianshenIsShow = false
|
||||
let louguIsShow = false
|
||||
|
||||
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
|
||||
const currentTab = tabs[0]
|
||||
if (currentTab) {
|
||||
const url = new URL(currentTab.url)
|
||||
const { hostname, pathname } = url
|
||||
csdnIsShow = hostname.includes("csdn")
|
||||
zhihuIsShow = hostname.includes("zhihu")
|
||||
baiduIsShow = hostname.includes("baidu")
|
||||
jianshuIsShow = hostname.includes("jianshu")
|
||||
jb51IsShow = hostname.includes("jb51")
|
||||
cnblogsIsShow = hostname.includes("cnblogs")
|
||||
ctoIsShow = hostname.includes("51cto")
|
||||
juejinIsShow = hostname.includes("juejin")
|
||||
phpIsShow = hostname.includes("php")
|
||||
oschinaIsShow = hostname.includes("oschina")
|
||||
segmentfaultIsShow = hostname.includes("segmentfault")
|
||||
mediumIsShow = hostname.includes("medium")
|
||||
paywallbusterIsShow = hostname.includes("paywallbuster")
|
||||
doc360IsShow = hostname.includes("360doc")
|
||||
pianshenIsShow = hostname.includes("pianshen")
|
||||
louguIsShow = hostname.includes("lougu")
|
||||
|
||||
if (hostname.includes("weixin")) {
|
||||
if (pathname.includes("cgi-bin")) {
|
||||
mpIsShow = true
|
||||
} else {
|
||||
weixinIsShow = true
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export default function Content() {
|
||||
const csdnRef = useRef<any>()
|
||||
const zhihuRef = useRef<any>()
|
||||
const baiduRef = useRef<any>()
|
||||
const juejinRef = useRef<any>()
|
||||
const oschinaRef = useRef<any>()
|
||||
const jianshuRef = useRef<any>()
|
||||
const jb51Ref = useRef<any>()
|
||||
const cnblogsRef = useRef<any>()
|
||||
const cto51Ref = useRef<any>()
|
||||
const phpRef = useRef<any>()
|
||||
const segmentfaultRef = useRef<any>()
|
||||
const weixinRef = useRef<any>()
|
||||
const customRef = useRef<any>()
|
||||
const appRef = useRef<any>()
|
||||
const [csdnIsShow, setCsdnIsShow] = useState<boolean>(false)
|
||||
const [zhihuIsShow, setZhihuIsShow] = useState<boolean>(false)
|
||||
const [baiduIsShow, setBaiduIsShow] = useState<boolean>(false)
|
||||
const [jianshuIsShow, setJianshuIsShow] = useState<boolean>(false)
|
||||
const [jb51IsShow, setJb51IsShow] = useState<boolean>(false)
|
||||
const [cnblogsIsShow, setCnblogsShow] = useState<boolean>(false)
|
||||
const [ctoIsShow, set51ctoIsShow] = useState<boolean>(false)
|
||||
const [juejinIsShow, setJuejinIsShow] = useState<boolean>(false)
|
||||
const [phpIsShow, setPhpIsShow] = useState<boolean>(false)
|
||||
const [oschinaIsShow, setOschinaIsShow] = useState<boolean>(false)
|
||||
const [segmentfaultIsShow, setSegmentfaultIsShow] = useState<boolean>(false)
|
||||
const [weixinIsShow, setWeixinIsShow] = useState<boolean>(false)
|
||||
const [mediumIsShow, setMediumIsShow] = useState<boolean>(false)
|
||||
|
||||
useEffect(() => {
|
||||
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
|
||||
const currentTab = tabs[0]
|
||||
if (currentTab) {
|
||||
const url = new URL(currentTab.url)
|
||||
const hostname = url.hostname
|
||||
|
||||
hostname.includes("csdn") && setCsdnIsShow(true)
|
||||
hostname.includes("zhihu") && setZhihuIsShow(true)
|
||||
hostname.includes("baidu") && setBaiduIsShow(true)
|
||||
hostname.includes("jianshu") && setJianshuIsShow(true)
|
||||
hostname.includes("jb51") && setJb51IsShow(true)
|
||||
hostname.includes("cnblogs") && setCnblogsShow(true)
|
||||
hostname.includes("51cto") && set51ctoIsShow(true)
|
||||
hostname.includes("juejin") && setJuejinIsShow(true)
|
||||
hostname.includes("php") && setPhpIsShow(true)
|
||||
hostname.includes("oschina") && setOschinaIsShow(true)
|
||||
hostname.includes("segmentfault") && setSegmentfaultIsShow(true)
|
||||
hostname.includes("weixin") && setWeixinIsShow(true)
|
||||
hostname.includes("medium") && setMediumIsShow(true)
|
||||
}
|
||||
})
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="content">
|
||||
{csdnIsShow ? <Csdn forwardRef={csdnRef} /> : <></>}
|
||||
{zhihuIsShow ? <Zhihu forwardRef={zhihuRef} /> : <></>}
|
||||
{baiduIsShow ? <Baidu forwardRef={baiduRef} /> : <></>}
|
||||
{jianshuIsShow ? <Jianshu forwardRef={jianshuRef} /> : <></>}
|
||||
{jb51IsShow ? <Jb51 forwardRef={jb51Ref} /> : <></>}
|
||||
{cnblogsIsShow ? <Cnblogs forwardRef={cnblogsRef} /> : <></>}
|
||||
{ctoIsShow ? <Cto51 forwardRef={cto51Ref} /> : <></>}
|
||||
{csdnIsShow ? <Csdn /> : <></>}
|
||||
{zhihuIsShow ? <Zhihu /> : <></>}
|
||||
{baiduIsShow ? <Baidu /> : <></>}
|
||||
{jianshuIsShow ? <Jianshu /> : <></>}
|
||||
{jb51IsShow ? <Jb51 /> : <></>}
|
||||
{cnblogsIsShow ? <Cnblogs /> : <></>}
|
||||
{ctoIsShow ? <Cto51 /> : <></>}
|
||||
{juejinIsShow ? <Juejin /> : <></>}
|
||||
{phpIsShow ? <Php forwardRef={phpRef} /> : <></>}
|
||||
{phpIsShow ? <Php /> : <></>}
|
||||
{oschinaIsShow ? <Oschina /> : <></>}
|
||||
{segmentfaultIsShow ? <Segmentfault /> : <></>}
|
||||
{weixinIsShow ? <Weixin /> : <></>}
|
||||
{mediumIsShow ? <Medium /> : <></>}
|
||||
{mpIsShow ? <Mp /> : <></>}
|
||||
{paywallbusterIsShow ? <Paywallbuster /> : <></>}
|
||||
{doc360IsShow ? <Doc360 /> : <></>}
|
||||
{pianshenIsShow ? <Pianshen /> : <></>}
|
||||
{louguIsShow ? <Lougu /> : <></>}
|
||||
<Custom />
|
||||
<Config forwardRef={customRef} />
|
||||
<Config />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import { useStorage } from "@plasmohq/storage/hook"
|
||||
import CssCode from "~component/items/cssCode"
|
||||
import DownloadHtml from "~component/items/downloadHtml"
|
||||
import DownloadMarkdown from "~component/items/downloadMarkdown"
|
||||
import DownloadPdf from "~component/items/downloadPdf"
|
||||
import EditMarkdown from "~component/items/editMarkdown"
|
||||
import ShowTag from "~component/items/showTag"
|
||||
import { i18n } from "~tools"
|
||||
@@ -142,13 +141,11 @@ export default function Csdn({ forwardRef }) {
|
||||
htmlFor="csdn-closeRedirectModal"
|
||||
className="codebox-switch"></label>
|
||||
</div>
|
||||
<ShowTag name="csdn"></ShowTag>
|
||||
<CssCode name="csdn"></CssCode>
|
||||
<ShowTag name="csdn"></ShowTag>
|
||||
<EditMarkdown name="csdn"></EditMarkdown>
|
||||
<DownloadMarkdown name="csdn"></DownloadMarkdown>
|
||||
<DownloadHtml name="csdn"></DownloadHtml>
|
||||
<DownloadPdf name="csdn"></DownloadPdf>
|
||||
</fieldset>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,45 +5,17 @@ import { sendToContentScript } from "@plasmohq/messaging"
|
||||
import CssCode from "~component/items/cssCode"
|
||||
import DownloadHtml from "~component/items/downloadHtml"
|
||||
import DownloadMarkdown from "~component/items/downloadMarkdown"
|
||||
import DownloadPdf from "~component/items/downloadPdf"
|
||||
import EditMarkdown from "~component/items/editMarkdown"
|
||||
import ParseMarkdown from "~component/items/parseMarkdown"
|
||||
import { i18n } from "~tools"
|
||||
|
||||
export default function Custom() {
|
||||
function makerQRPost() {
|
||||
sendToContentScript({
|
||||
name: "app-makerQRPost"
|
||||
})
|
||||
}
|
||||
function getArticle() {
|
||||
sendToContentScript({
|
||||
name: "app-getArticle"
|
||||
})
|
||||
}
|
||||
return (
|
||||
<fieldset>
|
||||
<legend>{i18n("customConfig")}</legend>
|
||||
<CssCode name="custom"></CssCode>
|
||||
<ParseMarkdown name="custom" />
|
||||
<EditMarkdown name="custom" />
|
||||
<DownloadMarkdown name="custom" />
|
||||
<DownloadHtml name="custom" />
|
||||
<DownloadPdf name="custom" />
|
||||
<div className="item download" onClick={makerQRPost}>
|
||||
<span>
|
||||
<StarTwoTone twoToneColor="#eb2f96" style={{ marginRight: "5px" }} />
|
||||
{i18n("makerQRPost")}
|
||||
</span>
|
||||
<DownloadOutlined style={{ color: "#52c41a", fontSize: "16px" }} />
|
||||
</div>
|
||||
<div className="item download" onClick={getArticle}>
|
||||
<span>
|
||||
<StarTwoTone twoToneColor="#eb2f96" style={{ marginRight: "5px" }} />
|
||||
{i18n("getArticle")}
|
||||
</span>
|
||||
<DownloadOutlined style={{ color: "#52c41a", fontSize: "16px" }} />
|
||||
</div>
|
||||
<EditMarkdown name="custom"></EditMarkdown>
|
||||
<DownloadMarkdown name="custom"></DownloadMarkdown>
|
||||
<DownloadHtml name="custom"></DownloadHtml>
|
||||
</fieldset>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,9 +5,7 @@ import { useStorage } from "@plasmohq/storage/hook"
|
||||
import CssCode from "~component/items/cssCode"
|
||||
import DownloadHtml from "~component/items/downloadHtml"
|
||||
import DownloadMarkdown from "~component/items/downloadMarkdown"
|
||||
import DownloadPdf from "~component/items/downloadPdf"
|
||||
import EditMarkdown from "~component/items/editMarkdown"
|
||||
import ShowTag from "~component/items/showTag"
|
||||
import { i18n } from "~tools"
|
||||
|
||||
export default function Jb51({ forwardRef }) {
|
||||
@@ -54,12 +52,10 @@ export default function Jb51({ forwardRef }) {
|
||||
/>
|
||||
<label className="codebox-switch" htmlFor="jb51-copyCode"></label>
|
||||
</div>
|
||||
<ShowTag name="jb51"></ShowTag>
|
||||
<CssCode name="jb51"></CssCode>
|
||||
<EditMarkdown name="jb51"></EditMarkdown>
|
||||
<DownloadMarkdown name="jb51"></DownloadMarkdown>
|
||||
<DownloadHtml name="jb51"></DownloadHtml>
|
||||
<DownloadPdf name="jb51"></DownloadPdf>
|
||||
</fieldset>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,9 +5,7 @@ import { useStorage } from "@plasmohq/storage/hook"
|
||||
import CssCode from "~component/items/cssCode"
|
||||
import DownloadHtml from "~component/items/downloadHtml"
|
||||
import DownloadMarkdown from "~component/items/downloadMarkdown"
|
||||
import DownloadPdf from "~component/items/downloadPdf"
|
||||
import EditMarkdown from "~component/items/editMarkdown"
|
||||
import ShowTag from "~component/items/showTag"
|
||||
import { i18n } from "~tools"
|
||||
|
||||
export default function Jianshu({ forwardRef }) {
|
||||
@@ -76,12 +74,10 @@ export default function Jianshu({ forwardRef }) {
|
||||
className="codebox-switch"
|
||||
htmlFor="jianshu-autoOpenCode"></label>
|
||||
</div>
|
||||
<ShowTag name="jianshu"></ShowTag>
|
||||
<CssCode name="jianshu"></CssCode>
|
||||
<EditMarkdown name="jianshu"></EditMarkdown>
|
||||
<DownloadMarkdown name="jianshu"></DownloadMarkdown>
|
||||
<DownloadHtml name="jianshu"></DownloadHtml>
|
||||
<DownloadPdf name="jianshu"></DownloadPdf>
|
||||
</fieldset>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
import Options from "~component/items/options"
|
||||
import CssCode from "~component/items/cssCode"
|
||||
import DownloadHtml from "~component/items/downloadHtml"
|
||||
import DownloadMarkdown from "~component/items/downloadMarkdown"
|
||||
import EditMarkdown from "~component/items/editMarkdown"
|
||||
import ShowTag from "~component/items/showTag"
|
||||
import { i18n } from "~tools"
|
||||
|
||||
export default function Juejin() {
|
||||
return <Options name="juejin" />
|
||||
return (
|
||||
<fieldset>
|
||||
<legend>{i18n("juejinConfig")}</legend>
|
||||
<CssCode name="juejin"></CssCode>
|
||||
<ShowTag name="juejin"></ShowTag>
|
||||
<EditMarkdown name="juejin"></EditMarkdown>
|
||||
<DownloadMarkdown name="juejin"></DownloadMarkdown>
|
||||
<DownloadHtml name="juejin"></DownloadHtml>
|
||||
</fieldset>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
import Options from "~component/items/options"
|
||||
|
||||
export default function Lougu() {
|
||||
return <Options name="lougu" />
|
||||
}
|
||||
@@ -1,5 +1,19 @@
|
||||
import Options from "~component/items/options"
|
||||
import CssCode from "~component/items/cssCode"
|
||||
import DownloadHtml from "~component/items/downloadHtml"
|
||||
import DownloadMarkdown from "~component/items/downloadMarkdown"
|
||||
import EditMarkdown from "~component/items/editMarkdown"
|
||||
import ShowTag from "~component/items/showTag"
|
||||
import { i18n } from "~tools"
|
||||
|
||||
export default function Medium() {
|
||||
return <Options name="medium" />
|
||||
return (
|
||||
<fieldset>
|
||||
<legend>{i18n("mediumConfig")}</legend>
|
||||
<CssCode name="medium"></CssCode>
|
||||
<ShowTag name="medium"></ShowTag>
|
||||
<EditMarkdown name="medium"></EditMarkdown>
|
||||
<DownloadMarkdown name="medium"></DownloadMarkdown>
|
||||
<DownloadHtml name="medium"></DownloadHtml>
|
||||
</fieldset>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import { BookOutlined, StarTwoTone } from "@ant-design/icons"
|
||||
|
||||
import { sendToContentScript } from "@plasmohq/messaging"
|
||||
|
||||
import { i18n } from "~tools"
|
||||
|
||||
export default function Weixin() {
|
||||
async function getThumbMedia() {
|
||||
sendToContentScript({
|
||||
name: `mp-getMediaResources`
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<fieldset>
|
||||
<legend>{i18n("weixinConfig")}</legend>
|
||||
<div className="item download" onClick={getThumbMedia}>
|
||||
<span>
|
||||
<StarTwoTone twoToneColor="#eb2f96" style={{ marginRight: "5px" }} />
|
||||
{i18n("getMediaResources")}
|
||||
</span>
|
||||
<BookOutlined style={{ color: "#52c41a", fontSize: "16px" }} />
|
||||
</div>
|
||||
</fieldset>
|
||||
)
|
||||
}
|
||||
@@ -1,5 +1,17 @@
|
||||
import Options from "~component/items/options"
|
||||
import CssCode from "~component/items/cssCode"
|
||||
import DownloadHtml from "~component/items/downloadHtml"
|
||||
import DownloadMarkdown from "~component/items/downloadMarkdown"
|
||||
import EditMarkdown from "~component/items/editMarkdown"
|
||||
import { i18n } from "~tools"
|
||||
|
||||
export default function Oschina() {
|
||||
return <Options name="oschina" />
|
||||
return (
|
||||
<fieldset>
|
||||
<legend>{i18n("oschinaConfig")}</legend>
|
||||
<CssCode name="oschina"></CssCode>
|
||||
<EditMarkdown name="oschina"></EditMarkdown>
|
||||
<DownloadMarkdown name="oschina"></DownloadMarkdown>
|
||||
<DownloadHtml name="oschina"></DownloadHtml>
|
||||
</fieldset>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
import Options from "~component/items/options"
|
||||
|
||||
export default function Paywallbuster() {
|
||||
return <Options name="paywallbuster" />
|
||||
}
|
||||
@@ -5,9 +5,7 @@ import { useStorage } from "@plasmohq/storage/hook"
|
||||
import CssCode from "~component/items/cssCode"
|
||||
import DownloadHtml from "~component/items/downloadHtml"
|
||||
import DownloadMarkdown from "~component/items/downloadMarkdown"
|
||||
import DownloadPdf from "~component/items/downloadPdf"
|
||||
import EditMarkdown from "~component/items/editMarkdown"
|
||||
import ShowTag from "~component/items/showTag"
|
||||
import { i18n } from "~tools"
|
||||
|
||||
export default function Php({ forwardRef }) {
|
||||
@@ -55,12 +53,11 @@ export default function Php({ forwardRef }) {
|
||||
/>
|
||||
<label htmlFor="php-closeLoginModal" className="codebox-switch"></label>
|
||||
</div>
|
||||
<CssCode name="php" />
|
||||
<ShowTag name="php" />
|
||||
<EditMarkdown name="php" />
|
||||
<DownloadMarkdown name="php" />
|
||||
<DownloadHtml name="php" />
|
||||
<DownloadPdf name="php" />
|
||||
<CssCode name="php"></CssCode>
|
||||
<EditMarkdown name="php"></EditMarkdown>
|
||||
<DownloadMarkdown name="php"></DownloadMarkdown>
|
||||
<DownloadHtml name="php"></DownloadHtml>
|
||||
<CssCode name="php"></CssCode>
|
||||
</fieldset>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
import Options from "~component/items/options"
|
||||
|
||||
export default function Pianshen() {
|
||||
return <Options name="pianshen" />
|
||||
}
|
||||
@@ -1,5 +1,17 @@
|
||||
import Options from "~component/items/options"
|
||||
import CssCode from "~component/items/cssCode"
|
||||
import DownloadHtml from "~component/items/downloadHtml"
|
||||
import DownloadMarkdown from "~component/items/downloadMarkdown"
|
||||
import EditMarkdown from "~component/items/editMarkdown"
|
||||
import { i18n } from "~tools"
|
||||
|
||||
export default function Segmentfault() {
|
||||
return <Options name="segmentfault" />
|
||||
return (
|
||||
<fieldset>
|
||||
<legend>{i18n("segmentfaultConfig")}</legend>
|
||||
<CssCode name="segmentfault"></CssCode>
|
||||
<EditMarkdown name="segmentfault"></EditMarkdown>
|
||||
<DownloadMarkdown name="segmentfault"></DownloadMarkdown>
|
||||
<DownloadHtml name="segmentfault"></DownloadHtml>
|
||||
</fieldset>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
import { DownloadOutlined, StarTwoTone } from "@ant-design/icons"
|
||||
|
||||
import { sendToContentScript } from "@plasmohq/messaging"
|
||||
|
||||
import CssCode from "~component/items/cssCode"
|
||||
import DownloadHtml from "~component/items/downloadHtml"
|
||||
import DownloadImages from "~component/items/downloadImages"
|
||||
import DownloadMarkdown from "~component/items/downloadMarkdown"
|
||||
import DownloadPdf from "~component/items/downloadPdf"
|
||||
import EditMarkdown from "~component/items/editMarkdown"
|
||||
@@ -12,29 +7,15 @@ import ShowTag from "~component/items/showTag"
|
||||
import { i18n } from "~tools"
|
||||
|
||||
export default function Weixin() {
|
||||
async function getThumbMedia() {
|
||||
sendToContentScript({
|
||||
name: `weixin-getThumbMedia`
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<fieldset>
|
||||
<legend>{i18n("weixinConfig")}</legend>
|
||||
<CssCode name="weixin" />
|
||||
<ShowTag name="weixin" />
|
||||
<EditMarkdown name="weixin" />
|
||||
<DownloadMarkdown name="weixin" />
|
||||
<DownloadHtml name="weixin" />
|
||||
<DownloadPdf name="weixin" />
|
||||
<DownloadImages name="weixin" />
|
||||
<div className="item download" onClick={getThumbMedia}>
|
||||
<span>
|
||||
<StarTwoTone twoToneColor="#eb2f96" style={{ marginRight: "5px" }} />
|
||||
{i18n("getThumbMedia")}
|
||||
</span>
|
||||
<DownloadOutlined style={{ color: "#52c41a", fontSize: "16px" }} />
|
||||
</div>
|
||||
<CssCode name="weixin"></CssCode>
|
||||
<ShowTag name="weixin"></ShowTag>
|
||||
<EditMarkdown name="weixin"></EditMarkdown>
|
||||
<DownloadMarkdown name="weixin"></DownloadMarkdown>
|
||||
<DownloadHtml name="weixin"></DownloadHtml>
|
||||
<DownloadPdf name="weixin"></DownloadPdf>
|
||||
</fieldset>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,9 +5,7 @@ import { useStorage } from "@plasmohq/storage/hook"
|
||||
import CssCode from "~component/items/cssCode"
|
||||
import DownloadHtml from "~component/items/downloadHtml"
|
||||
import DownloadMarkdown from "~component/items/downloadMarkdown"
|
||||
import DownloadPdf from "~component/items/downloadPdf"
|
||||
import EditMarkdown from "~component/items/editMarkdown"
|
||||
import ShowTag from "~component/items/showTag"
|
||||
import { i18n } from "~tools"
|
||||
|
||||
export default function Zhihu({ forwardRef }) {
|
||||
@@ -74,12 +72,10 @@ export default function Zhihu({ forwardRef }) {
|
||||
/>
|
||||
<label className="codebox-switch" htmlFor="zhihu-autoOpenCode"></label>
|
||||
</div>
|
||||
<CssCode name="zhihu" />
|
||||
<ShowTag name="zhihu" />
|
||||
<EditMarkdown name="zhihu" />
|
||||
<DownloadMarkdown name="zhihu" />
|
||||
<DownloadHtml name="zhihu" />
|
||||
<DownloadPdf name="zhihu" />
|
||||
<CssCode name="zhihu"></CssCode>
|
||||
<EditMarkdown name="zhihu"></EditMarkdown>
|
||||
<DownloadMarkdown name="weixin"></DownloadMarkdown>
|
||||
<DownloadHtml name="weixin"></DownloadHtml>
|
||||
</fieldset>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
export default function TagBtnStyle() {
|
||||
const style = document.createElement("style")
|
||||
style.textContent = `
|
||||
.codebox-tagBtn .btn:hover {
|
||||
color: #fff;
|
||||
background: #1e80ff;
|
||||
border-radius: 3px;
|
||||
}
|
||||
`
|
||||
return style
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
import imageSrc from "raw:~/public/wx/xcx.jpg"
|
||||
import React, { useEffect, useState } from "react"
|
||||
|
||||
import { TOTP } from "~utils/totp"
|
||||
|
||||
interface QRCodeModalProps {
|
||||
onConfirm: () => void
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
const styles = {
|
||||
overlay: {
|
||||
position: "fixed" as const,
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
zIndex: 1000
|
||||
},
|
||||
content: {
|
||||
backgroundColor: "white",
|
||||
padding: "2rem",
|
||||
borderRadius: "8px",
|
||||
position: "relative" as const,
|
||||
maxWidth: "90%",
|
||||
boxShadow: "0 2px 10px rgba(0, 0, 0, 0.1)"
|
||||
},
|
||||
closeButton: {
|
||||
position: "absolute" as const,
|
||||
top: "10px",
|
||||
right: "10px",
|
||||
background: "none",
|
||||
border: "none",
|
||||
fontSize: "18px",
|
||||
cursor: "pointer",
|
||||
padding: "0.5rem"
|
||||
},
|
||||
qrcodeBox: {
|
||||
width: "100%",
|
||||
textAlign: "center" as const
|
||||
},
|
||||
qrcodeImage: {
|
||||
maxWidth: "260px",
|
||||
width: "100%",
|
||||
height: "auto",
|
||||
margin: "0px auto"
|
||||
},
|
||||
scanTip: {
|
||||
textAlign: "center" as const,
|
||||
color: "#666"
|
||||
},
|
||||
captchaSection: {
|
||||
marginTop: "1.5rem",
|
||||
borderTop: "1px solid #eee",
|
||||
paddingTop: "1.5rem"
|
||||
},
|
||||
captchaRow: {
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginBottom: "1rem"
|
||||
},
|
||||
captchaText: {
|
||||
fontSize: "16px",
|
||||
letterSpacing: "2px",
|
||||
color: "#333"
|
||||
},
|
||||
inputGroup: {
|
||||
display: "flex",
|
||||
gap: "0.5rem"
|
||||
},
|
||||
input: {
|
||||
flex: 1,
|
||||
padding: "0.8rem",
|
||||
border: "1px solid #ddd",
|
||||
borderRadius: "4px",
|
||||
fontSize: "14px",
|
||||
outline: "none",
|
||||
"&:focus": {
|
||||
borderColor: "#007bff"
|
||||
}
|
||||
},
|
||||
verifyButton: {
|
||||
padding: "0.8rem 1.5rem",
|
||||
backgroundColor: "#007bff",
|
||||
color: "white",
|
||||
border: "none",
|
||||
borderRadius: "4px",
|
||||
cursor: "pointer",
|
||||
"&:hover": {
|
||||
backgroundColor: "#0056b3"
|
||||
}
|
||||
},
|
||||
errorText: {
|
||||
color: "#ff4444",
|
||||
fontSize: "14px",
|
||||
marginTop: "6px"
|
||||
}
|
||||
}
|
||||
|
||||
export default function QRCodeModal({ onClose, onConfirm }: QRCodeModalProps) {
|
||||
const [inputCode, setInputCode] = useState<string>("")
|
||||
const [isValid, setIsValid] = useState<boolean | null>(null)
|
||||
|
||||
const handleVerify = () => {
|
||||
const formattedInput = inputCode.replace(/\s/g, "")
|
||||
const secretKey = process.env.PLASMO_PUBLIC_CODEBOX_SECRET4
|
||||
|
||||
if (
|
||||
formattedInput.length == 6 &&
|
||||
TOTP.verifyTOTP(secretKey, formattedInput)
|
||||
) {
|
||||
setIsValid(true)
|
||||
onConfirm()
|
||||
} else if (process.env.PLASMO_PUBLIC_CODEBOX_SECRET3 == formattedInput) {
|
||||
setIsValid(true)
|
||||
onConfirm()
|
||||
} else {
|
||||
setIsValid(false)
|
||||
}
|
||||
}
|
||||
|
||||
// 在原有return中添加:
|
||||
return (
|
||||
<div style={styles.overlay}>
|
||||
<div style={styles.content}>
|
||||
<button style={styles.closeButton} onClick={onClose} aria-label="Close">
|
||||
×
|
||||
</button>
|
||||
|
||||
{imageSrc && (
|
||||
<div style={styles.qrcodeBox}>
|
||||
<img
|
||||
src={imageSrc}
|
||||
alt="WeChat QR Code"
|
||||
style={styles.qrcodeImage}
|
||||
/>
|
||||
<div style={styles.scanTip}>扫描二维码获取验证码</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 新增验证码区域 */}
|
||||
<div style={styles.captchaSection}>
|
||||
<div style={styles.inputGroup}>
|
||||
<input
|
||||
type="text"
|
||||
value={inputCode}
|
||||
onChange={(e) => {
|
||||
// 只允许数字和空格
|
||||
const val = e.target.value.replace(/[^\d\s]/g, "")
|
||||
setInputCode(val)
|
||||
setIsValid(null) // 清除验证状态
|
||||
}}
|
||||
placeholder="请输入验证码"
|
||||
style={{
|
||||
...styles.input,
|
||||
borderColor: isValid === false ? "#ff4444" : "#ddd"
|
||||
}}
|
||||
maxLength={11} // 6数字+5空格
|
||||
/>
|
||||
<button style={styles.verifyButton} onClick={handleVerify}>
|
||||
验证
|
||||
</button>
|
||||
</div>
|
||||
{isValid === false && (
|
||||
<div style={styles.errorText}>验证码错误,请重新输入</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,213 +0,0 @@
|
||||
import React, { useEffect, useRef, useState } from "react"
|
||||
|
||||
import { useMessage } from "@plasmohq/messaging/hook"
|
||||
import { useStorage } from "@plasmohq/storage/dist/hook"
|
||||
|
||||
import ValidModal from "~component/ui/validModal"
|
||||
import { addCss, saveHtml, saveMarkdown } from "~tools"
|
||||
import { useEditMarkdown } from "~utils/editMarkdownHook"
|
||||
import { useParseMarkdown } from "~utils/parseMarkdownHook"
|
||||
import { Print } from "~utils/print"
|
||||
import Turndown from "~utils/turndown"
|
||||
|
||||
import Tooltip from "../ui/tooltip"
|
||||
|
||||
const turndownService = Turndown()
|
||||
|
||||
export default function CustomDomSelector() {
|
||||
const [aiType, setAiType] = useStorage("app-aiType")
|
||||
const [position, setPosition] = useState({ top: 0, left: 0 })
|
||||
const [isReady, setIsReady] = useState(false)
|
||||
const [isSelect, setIsSelect] = useState(false)
|
||||
const [isModalOpen, setIsModalOpen] = useState(false)
|
||||
const downloadType = useRef("")
|
||||
const [editContent, setEditContent] = useEditMarkdown()
|
||||
const [parseContent, setParseContent] = useParseMarkdown()
|
||||
|
||||
const articleTitle = document
|
||||
.querySelector<HTMLElement>("head title")
|
||||
?.innerText.trim()
|
||||
|
||||
useEffect(() => {
|
||||
if (aiType) {
|
||||
addCss(`.codebox-current { outline: 2px solid #42b88350 !important; }`)
|
||||
if (isReady) {
|
||||
addEventListeners()
|
||||
} else {
|
||||
removeEventListeners()
|
||||
}
|
||||
}
|
||||
return () => {
|
||||
removeEventListeners()
|
||||
}
|
||||
}, [aiType, isReady, isSelect])
|
||||
|
||||
const addEventListeners = () => {
|
||||
document.addEventListener("mousemove", handleMouseMove)
|
||||
document.addEventListener("click", handleClick)
|
||||
}
|
||||
|
||||
const removeEventListeners = () => {
|
||||
document.removeEventListener("mousemove", handleMouseMove)
|
||||
document.removeEventListener("click", handleClick)
|
||||
}
|
||||
|
||||
const handleMouseMove = (event: MouseEvent) => {
|
||||
if (isReady && !isSelect) {
|
||||
const target = event.target as HTMLElement
|
||||
highlightElement(target)
|
||||
}
|
||||
}
|
||||
|
||||
const handleClick = (event: MouseEvent) => {
|
||||
if (isReady) {
|
||||
const target = event.target as HTMLElement
|
||||
const tooltip = target.closest(".codebox-tooltip")
|
||||
const modal = target.closest(".codebox-modal")
|
||||
const csui = target.closest("#codebox-csui")
|
||||
|
||||
if (!tooltip && !modal && !csui) {
|
||||
setIsSelect(true)
|
||||
highlightElement(target)
|
||||
updateTooltipPosition(target)
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const highlightElement = (element: HTMLElement) => {
|
||||
removeHighlight()
|
||||
element.classList.add("codebox-current")
|
||||
}
|
||||
|
||||
const removeHighlight = () => {
|
||||
const currentList = document.querySelectorAll(".codebox-current")
|
||||
currentList.forEach((el) => el.classList.remove("codebox-current"))
|
||||
}
|
||||
|
||||
const updateTooltipPosition = (element: HTMLElement) => {
|
||||
const rect = element.getBoundingClientRect()
|
||||
const distanceTop = rect.top + window.scrollY
|
||||
const distanceLeft = rect.left + window.scrollX
|
||||
const top =
|
||||
distanceTop < 50 ? distanceTop + rect.height + 5 : distanceTop - 40
|
||||
const left = distanceLeft + 5
|
||||
|
||||
setPosition({ top: top, left: left })
|
||||
window.scrollTo({ top: top - 150, behavior: "smooth" })
|
||||
}
|
||||
|
||||
useMessage(async (req: any, res: any) => {
|
||||
const name = req.name
|
||||
const isApp = name.split("-")[0] == "app"
|
||||
console.log(isApp)
|
||||
if (name && !isApp) {
|
||||
const type = name.split("-")[1]
|
||||
setCustom(type)
|
||||
}
|
||||
})
|
||||
|
||||
const setCustom = (type: string) => {
|
||||
downloadType.current = type
|
||||
setIsReady(true)
|
||||
setIsSelect(false)
|
||||
}
|
||||
|
||||
const handleOkModal = () => {
|
||||
const selector = document.querySelector<HTMLElement>(".codebox-current")
|
||||
if (!selector || !downloadType.current) return
|
||||
|
||||
selector.classList.remove("codebox-current")
|
||||
|
||||
switch (downloadType.current) {
|
||||
case "downloadHtml":
|
||||
saveHtml(selector, articleTitle)
|
||||
break
|
||||
case "downloadMarkdown":
|
||||
const markdown = turndownService.turndown(selector)
|
||||
saveMarkdown(markdown, articleTitle)
|
||||
break
|
||||
case "editMarkdown":
|
||||
setEditContent(selector)
|
||||
break
|
||||
case "parseMarkdown":
|
||||
setParseContent(selector, aiType)
|
||||
break
|
||||
case "downloadPdf":
|
||||
Print.print(selector, { title: articleTitle })
|
||||
.then(() => console.log("Printing complete"))
|
||||
.catch((error) => console.error("Printing failed:", error))
|
||||
break
|
||||
}
|
||||
|
||||
resetState()
|
||||
setTimeout(() => {
|
||||
setIsModalOpen(false)
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
const handleConfirm = () => {
|
||||
setIsModalOpen(true)
|
||||
}
|
||||
|
||||
const handleCancel = () => {
|
||||
resetState()
|
||||
}
|
||||
|
||||
const resetState = () => {
|
||||
removeHighlight()
|
||||
setIsSelect(false)
|
||||
setIsReady(false)
|
||||
}
|
||||
|
||||
const navigateElement = (direction: "parent" | "child" | "prev" | "next") => {
|
||||
const selector = document.querySelector(".codebox-current")
|
||||
if (!selector) return
|
||||
let newElement: HTMLElement | null = null
|
||||
switch (direction) {
|
||||
case "parent":
|
||||
newElement = selector.parentElement
|
||||
break
|
||||
case "child":
|
||||
newElement = selector.firstElementChild as HTMLElement
|
||||
break
|
||||
case "prev":
|
||||
newElement = selector.previousElementSibling as HTMLElement
|
||||
break
|
||||
case "next":
|
||||
newElement = selector.nextElementSibling as HTMLElement
|
||||
break
|
||||
}
|
||||
|
||||
if (newElement) {
|
||||
highlightElement(newElement)
|
||||
updateTooltipPosition(newElement)
|
||||
}
|
||||
}
|
||||
|
||||
const handleCancelModal = () => {
|
||||
setIsModalOpen(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{isSelect && (
|
||||
<Tooltip
|
||||
left={position.left}
|
||||
top={position.top}
|
||||
onConfirm={handleConfirm}
|
||||
onCancel={handleCancel}
|
||||
onNavigate={navigateElement}
|
||||
/>
|
||||
)}
|
||||
{isModalOpen && (
|
||||
<ValidModal
|
||||
onClose={handleCancelModal}
|
||||
onConfirm={handleOkModal}
|
||||
type={downloadType.current}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
import React from "react"
|
||||
|
||||
import ValidateContent from "~component/contents/validateContent"
|
||||
|
||||
const Modal = ({ isOpen, onClose, onConfirm, message }) => {
|
||||
if (!isOpen) return null
|
||||
|
||||
const modalOverlayStyle = {
|
||||
position: "fixed",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
background: "rgba(0, 0, 0, 0.5)",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
zIndex: 1000
|
||||
}
|
||||
|
||||
const modalStyle = {
|
||||
background: "white",
|
||||
padding: "20px",
|
||||
borderRadius: "8px",
|
||||
boxShadow: "0 4px 8px rgba(0, 0, 0, 0.1)",
|
||||
textAlign: "center"
|
||||
}
|
||||
|
||||
const modalButtonsStyle = {
|
||||
marginTop: "20px"
|
||||
}
|
||||
|
||||
const buttonStyle = {
|
||||
borderRadius: "4px",
|
||||
padding: "2px 7px",
|
||||
margin: "0 10px",
|
||||
fontSize: "16px",
|
||||
cursor: "pointer"
|
||||
}
|
||||
|
||||
const cancelBtnStyle = {
|
||||
...buttonStyle,
|
||||
backgroundColor: "#d9363e",
|
||||
border: "1px solid #d9363e",
|
||||
color: "#fff"
|
||||
}
|
||||
|
||||
const confirmBtnStyle = {
|
||||
...buttonStyle,
|
||||
backgroundColor: "#1677FF",
|
||||
border: "1px solid #1677FF",
|
||||
color: "#fff"
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={modalOverlayStyle as React.CSSProperties}>
|
||||
<div style={modalStyle as React.CSSProperties}>
|
||||
<ValidateContent
|
||||
type="parseMarkdown"
|
||||
handleOk={onConfirm}
|
||||
handleCancel={onClose}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Modal
|
||||
@@ -1,66 +0,0 @@
|
||||
import { CloseOutlined } from "@ant-design/icons"
|
||||
import React, { useState } from "react"
|
||||
|
||||
import { i18n } from "~tools"
|
||||
|
||||
const tagsStyles = {
|
||||
tags: {
|
||||
height: "28px",
|
||||
display: "flex",
|
||||
cursor: "pointer",
|
||||
alignItems: "center",
|
||||
color: "#1e80ff",
|
||||
width: "160px",
|
||||
backgroundColor: "rgb(255, 255, 255, .3)",
|
||||
borderRadius: "5px",
|
||||
justifyContent: "space-between",
|
||||
padding: "0 8px",
|
||||
marginTop: "-20px",
|
||||
fontSize: "14px"
|
||||
}
|
||||
}
|
||||
|
||||
export default function Tags(props: any) {
|
||||
const [isShowTag, setIsShowTag] = useState(true)
|
||||
const handleEdit = () => {
|
||||
props.onEdit()
|
||||
}
|
||||
|
||||
const handleDownload = () => {
|
||||
props.onDownload()
|
||||
}
|
||||
|
||||
const handleParse = () => {
|
||||
props.onParse()
|
||||
}
|
||||
|
||||
const handlePrint = () => {
|
||||
props.onPrint()
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
setIsShowTag(false)
|
||||
}
|
||||
|
||||
return isShowTag ? (
|
||||
<div className="codebox-tagBtn" style={tagsStyles.tags}>
|
||||
<div onClick={handleEdit} className="btn">
|
||||
{i18n("edit")}
|
||||
</div>
|
||||
<div onClick={handleDownload} className="btn">
|
||||
{i18n("download")}
|
||||
</div>
|
||||
<div onClick={handlePrint} className="btn">
|
||||
{i18n("print")}
|
||||
</div>
|
||||
<div onClick={handleParse} className="btn">
|
||||
{i18n("parse")}
|
||||
</div>
|
||||
<div onClick={handleClose} className="btn">
|
||||
<CloseOutlined />
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
import qrcodeUrl from "raw:~/public/wx/gzh.jpg"
|
||||
import React, { useState } from "react"
|
||||
|
||||
import { i18n } from "~tools"
|
||||
import { editQRCodeImg } from "~utils/makerQRPost"
|
||||
|
||||
const boxStyles = {
|
||||
box: {
|
||||
position: "fixed" as const,
|
||||
border: "1px solid #D9DADC",
|
||||
left: "25px",
|
||||
top: "85px",
|
||||
width: "140px",
|
||||
padding: "16px",
|
||||
cursor: "pointer"
|
||||
},
|
||||
close: {
|
||||
position: "absolute" as const,
|
||||
top: "-5px",
|
||||
right: "0px",
|
||||
background: "none",
|
||||
border: "none",
|
||||
fontSize: "20px",
|
||||
cursor: "pointer",
|
||||
padding: "10px"
|
||||
},
|
||||
img: {
|
||||
width: "100%"
|
||||
},
|
||||
item: {
|
||||
color: "#000000",
|
||||
fontSize: "16px",
|
||||
marginBottom: "3px"
|
||||
}
|
||||
}
|
||||
|
||||
export default function ToolBox(props: any) {
|
||||
const [isShowTag, setIsShowTag] = useState(true)
|
||||
const handleGetDescription = () => {
|
||||
props.onGetDescription()
|
||||
}
|
||||
|
||||
const handleEditMarkdown = () => {
|
||||
props.onEditMarkdown()
|
||||
}
|
||||
|
||||
const handleDownloadMarkdown = () => {
|
||||
props.onDownloadMarkdown()
|
||||
}
|
||||
|
||||
const handleParseMarkdown = () => {
|
||||
props.onParseMarkdown()
|
||||
}
|
||||
|
||||
const handlePrint = () => {
|
||||
props.onPrint()
|
||||
}
|
||||
|
||||
const getArticle = () => {
|
||||
const href = encodeURIComponent(location.href)
|
||||
window.open(`https://paywallbuster.com/articles/?article=${href}`)
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
setIsShowTag(false)
|
||||
}
|
||||
|
||||
return isShowTag ? (
|
||||
<div
|
||||
id="ws_cmbm"
|
||||
className="ws_cmbmc"
|
||||
style={{ ...boxStyles.box, ...props.style }}>
|
||||
<button style={boxStyles.close} onClick={handleClose} aria-label="Close">
|
||||
×
|
||||
</button>
|
||||
<img src={qrcodeUrl} alt="qrcodeUrl" style={boxStyles.img} />
|
||||
<div style={boxStyles.item}>
|
||||
<a onClick={handleGetDescription}>{i18n("getDescription")}</a>
|
||||
</div>
|
||||
<div style={boxStyles.item}>
|
||||
<a onClick={handleEditMarkdown}>{i18n("editMarkdown")}</a>
|
||||
</div>
|
||||
<div style={boxStyles.item}>
|
||||
<a onClick={handleDownloadMarkdown}>{i18n("downloadMarkdown")}</a>
|
||||
</div>
|
||||
<div style={boxStyles.item}>
|
||||
<a onClick={handleParseMarkdown}>{i18n("parseMarkdown")}</a>
|
||||
</div>
|
||||
<div style={boxStyles.item}>
|
||||
<a onClick={handlePrint}>{i18n("downloadPdf")}</a>
|
||||
</div>
|
||||
<div style={boxStyles.item}>
|
||||
<a onClick={() => editQRCodeImg()}>{i18n("makerQRPost")}</a>
|
||||
</div>
|
||||
<div style={boxStyles.item}>
|
||||
<a onClick={() => getArticle()}>{i18n("getArticle")}</a>
|
||||
</div>
|
||||
<a style={boxStyles.item} href="https://www.code-box.fun" target="_blank">
|
||||
帮助
|
||||
</a>
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
import {
|
||||
CheckOutlined,
|
||||
CloseOutlined,
|
||||
DownSquareOutlined,
|
||||
LeftSquareOutlined,
|
||||
RightSquareOutlined,
|
||||
UpSquareOutlined
|
||||
} from "@ant-design/icons"
|
||||
import React from "react"
|
||||
|
||||
const tooltipStyles = {
|
||||
tooltip: {
|
||||
position: "absolute" as const,
|
||||
zIndex: "2147483641",
|
||||
backgroundColor: "#fff",
|
||||
border: "1px solid #eee",
|
||||
borderRadius: "5px",
|
||||
padding: "8px",
|
||||
boxShadow: "0 2px 8px rgba(0, 0, 0, 0.15)",
|
||||
width: "450px",
|
||||
display: "flex",
|
||||
justifyContent: "space-between"
|
||||
},
|
||||
button: {
|
||||
backgroundColor: "#fff",
|
||||
border: "1px solid #eee",
|
||||
color: "#000",
|
||||
borderRadius: "4px",
|
||||
padding: "2px 7px",
|
||||
fontSize: "14px",
|
||||
cursor: "pointer"
|
||||
},
|
||||
blueButton: {
|
||||
backgroundColor: "#1677FF",
|
||||
border: "1px solid #1677FF",
|
||||
color: "#fff",
|
||||
borderRadius: "4px",
|
||||
padding: "2px 7px",
|
||||
fontSize: "14px"
|
||||
},
|
||||
redButton: {
|
||||
backgroundColor: "#d9363e",
|
||||
border: "1px solid #d9363e",
|
||||
color: "#fff",
|
||||
borderRadius: "4px",
|
||||
padding: "2px 7px",
|
||||
fontSize: "14px"
|
||||
}
|
||||
}
|
||||
|
||||
export default function Tooltip(props: any) {
|
||||
const handleConfirm = () => {
|
||||
props.onConfirm()
|
||||
}
|
||||
|
||||
const navigateElement = (direction: "parent" | "child" | "prev" | "next") => {
|
||||
props.onNavigate(direction)
|
||||
}
|
||||
|
||||
const handleCancel = () => {
|
||||
props.onCancel()
|
||||
}
|
||||
|
||||
const setTooltipStyle = () => {
|
||||
return { ...tooltipStyles.tooltip, left: props.left, top: props.top }
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={setTooltipStyle()} className="codebox-tooltip">
|
||||
<button style={tooltipStyles.blueButton} onClick={handleConfirm}>
|
||||
<CheckOutlined /> 确定
|
||||
</button>
|
||||
<button
|
||||
style={tooltipStyles.button}
|
||||
onClick={() => navigateElement("parent")}>
|
||||
<UpSquareOutlined /> 父节点
|
||||
</button>
|
||||
<button
|
||||
style={tooltipStyles.button}
|
||||
onClick={() => navigateElement("child")}>
|
||||
<DownSquareOutlined /> 子节点
|
||||
</button>
|
||||
<button
|
||||
style={tooltipStyles.button}
|
||||
onClick={() => navigateElement("prev")}>
|
||||
<LeftSquareOutlined /> 上一个
|
||||
</button>
|
||||
<button
|
||||
style={tooltipStyles.button}
|
||||
onClick={() => navigateElement("next")}>
|
||||
<RightSquareOutlined /> 下一个
|
||||
</button>
|
||||
<button style={tooltipStyles.redButton} onClick={handleCancel}>
|
||||
<CloseOutlined /> 取消
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,227 +0,0 @@
|
||||
import dayjs from "dayjs"
|
||||
import qrcodeUrl from "raw:~/public/wx/gzh.jpg"
|
||||
import React, { useEffect, useRef, useState } from "react"
|
||||
|
||||
import { sendToBackground } from "@plasmohq/messaging"
|
||||
import { useStorage } from "@plasmohq/storage/dist/hook"
|
||||
|
||||
const styles = {
|
||||
overlay: {
|
||||
position: "fixed" as const,
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
zIndex: 1000
|
||||
},
|
||||
container: {
|
||||
width: "350px",
|
||||
padding: "2rem",
|
||||
position: "absolute" as const,
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
backgroundColor: "white",
|
||||
borderRadius: "5px",
|
||||
textAlign: "center" as const,
|
||||
boxShadow: "0 2px 10px rgba(0, 0, 0, 0.1)"
|
||||
},
|
||||
closeButton: {
|
||||
position: "absolute" as const,
|
||||
top: "10px",
|
||||
right: "10px",
|
||||
background: "none",
|
||||
border: "none",
|
||||
fontSize: "18px",
|
||||
cursor: "pointer",
|
||||
padding: "0.5rem"
|
||||
},
|
||||
activatedText: {
|
||||
fontSize: "16px",
|
||||
color: "red"
|
||||
},
|
||||
noticeText: {
|
||||
fontSize: "14px",
|
||||
color: "red"
|
||||
},
|
||||
helpLink: {
|
||||
cursor: "pointer"
|
||||
},
|
||||
qrcodeImage: {
|
||||
margin: "auto"
|
||||
},
|
||||
inputContainer: {
|
||||
marginTop: "10px",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center"
|
||||
},
|
||||
label: {
|
||||
display: "block",
|
||||
marginRight: "7px"
|
||||
},
|
||||
captchaSection: {
|
||||
marginTop: "1.5rem",
|
||||
borderTop: "1px solid #eee",
|
||||
paddingTop: "1.5rem"
|
||||
},
|
||||
captchaRow: {
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginBottom: "1rem"
|
||||
},
|
||||
captchaText: {
|
||||
fontSize: "16px",
|
||||
letterSpacing: "2px",
|
||||
color: "#333"
|
||||
},
|
||||
inputGroup: {
|
||||
display: "flex",
|
||||
gap: "0.5rem"
|
||||
},
|
||||
input: {
|
||||
flex: 1,
|
||||
padding: "0.8rem",
|
||||
border: "1px solid #ddd",
|
||||
borderRadius: "4px",
|
||||
fontSize: "16px",
|
||||
outline: "none",
|
||||
"&:focus": {
|
||||
borderColor: "#007bff"
|
||||
}
|
||||
},
|
||||
verifyButton: {
|
||||
padding: "0.8rem 1.5rem",
|
||||
backgroundColor: "#007bff",
|
||||
color: "white",
|
||||
border: "none",
|
||||
borderRadius: "4px",
|
||||
cursor: "pointer",
|
||||
"&:hover": {
|
||||
backgroundColor: "#0056b3"
|
||||
}
|
||||
},
|
||||
errorText: {
|
||||
color: "#ff4444",
|
||||
fontSize: "16px",
|
||||
marginTop: "0.5rem"
|
||||
}
|
||||
}
|
||||
|
||||
export default function ValidModal(props) {
|
||||
const [validTime, setValidTime] = useStorage("app-validTime", "1730390400")
|
||||
const [inputCode, setInputCode] = useState<string>("")
|
||||
const [isValid, setIsValid] = useState(true)
|
||||
|
||||
useEffect(() => {
|
||||
if (Number(validTime) > dayjs().unix()) {
|
||||
setTimeout(() => {
|
||||
handleSubmit()
|
||||
}, 1000)
|
||||
}
|
||||
}, [validTime])
|
||||
|
||||
function handleSubmit() {
|
||||
if (Number(validTime) > dayjs().unix()) {
|
||||
props.onConfirm()
|
||||
} else if (process.env.PLASMO_PUBLIC_CODEBOX_SECRET3 == inputCode) {
|
||||
let time = dayjs().add(3, "day").unix()
|
||||
setValidTime(String(time))
|
||||
setIsValid(true)
|
||||
props.onConfirm()
|
||||
} else {
|
||||
setIsValid(false)
|
||||
}
|
||||
}
|
||||
|
||||
function handleCancel() {
|
||||
props.onClose()
|
||||
}
|
||||
|
||||
function help() {
|
||||
sendToBackground({
|
||||
name: "tab",
|
||||
body: {
|
||||
url: "feed.html"
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const typeMap = {
|
||||
downloadHtml: "下载HTML",
|
||||
downloadMarkdown: "下载markdown",
|
||||
editMarkdown: "编辑markdown",
|
||||
parseMarkdown: "解析markdown",
|
||||
downloadPdf: "下载PDF"
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={styles.overlay} className="codebox-modal">
|
||||
<div style={styles.container}>
|
||||
<button
|
||||
style={styles.closeButton}
|
||||
onClick={handleCancel}
|
||||
aria-label="Close">
|
||||
×
|
||||
</button>
|
||||
{Number(validTime) > dayjs().unix() ? (
|
||||
<>
|
||||
<p style={styles.activatedText}>
|
||||
已激活!正在{typeMap[props.type]}...
|
||||
</p>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div style={styles.noticeText}>
|
||||
此功能需要关注公众号
|
||||
<p>
|
||||
【codebox代码助手】获取验证码(
|
||||
<a onClick={help} target="_blank" style={styles.helpLink}>
|
||||
帮助
|
||||
</a>
|
||||
)
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<img
|
||||
style={styles.qrcodeImage}
|
||||
src={qrcodeUrl}
|
||||
alt="微信公众号"
|
||||
/>
|
||||
</div>
|
||||
<div style={styles.captchaSection}>
|
||||
<div style={styles.inputGroup}>
|
||||
<input
|
||||
type="text"
|
||||
value={inputCode}
|
||||
onChange={(e) => {
|
||||
const val = e.target.value.replace(/[^\d\s]/g, "")
|
||||
setInputCode(val)
|
||||
setIsValid(null) // 清除验证状态
|
||||
}}
|
||||
placeholder="请输入验证码"
|
||||
style={{
|
||||
...styles.input,
|
||||
borderColor: isValid === false ? "#ff4444" : "#ddd"
|
||||
}}
|
||||
maxLength={11} // 6数字+5空格
|
||||
/>
|
||||
<button style={styles.verifyButton} onClick={handleSubmit}>
|
||||
验证
|
||||
</button>
|
||||
</div>
|
||||
{isValid === false && (
|
||||
<div style={styles.errorText}>验证码错误,请重新输入</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
import type {
|
||||
PlasmoCSConfig,
|
||||
PlasmoCSUIProps,
|
||||
PlasmoGetShadowHostId
|
||||
} from "plasmo"
|
||||
import React, { type FC } from "react"
|
||||
|
||||
import { useMessage } from "@plasmohq/messaging/hook"
|
||||
import { useStorage } from "@plasmohq/storage/dist/hook"
|
||||
|
||||
import ToolBox from "~component/ui/toolBox"
|
||||
import { saveHtml, saveMarkdown } from "~tools"
|
||||
import useCssCodeHook from "~utils/cssCodeHook"
|
||||
import { useEditMarkdown } from "~utils/editMarkdownHook"
|
||||
import { useParseMarkdown } from "~utils/parseMarkdownHook"
|
||||
import { Print } from "~utils/print"
|
||||
import Turndown from "~utils/turndown"
|
||||
|
||||
export const config: PlasmoCSConfig = {
|
||||
matches: ["https://*.360doc.com/content/*", "http://*.360doc.com/content/*"]
|
||||
}
|
||||
|
||||
const turndownService = Turndown()
|
||||
const articleTitle = document
|
||||
.querySelector<HTMLElement>("head title")
|
||||
.innerText.trim()
|
||||
|
||||
export const getShadowHostId: PlasmoGetShadowHostId = () => "codebox-360doc"
|
||||
|
||||
const PlasmoOverlay: FC<PlasmoCSUIProps> = () => {
|
||||
const [parseContent, setParseContent] = useParseMarkdown()
|
||||
const [allShowTag, setAllShowTag] = useStorage("config-allShowTag", true)
|
||||
const [showTag, setShowTag] = useStorage<boolean>("360doc-showTag", true)
|
||||
const [cssCode, runCss] = useCssCodeHook("360doc")
|
||||
const [content, setContent] = useEditMarkdown()
|
||||
|
||||
useMessage(async (req, res) => {
|
||||
if (req.name == "360doc-isShow") {
|
||||
res.send({ isShow: true })
|
||||
}
|
||||
if (req.name == "360doc-editMarkdown") {
|
||||
editMarkdown()
|
||||
}
|
||||
if (req.name == "360doc-downloadMarkdown") {
|
||||
downloadMarkdown()
|
||||
}
|
||||
if (req.name == "360doc-downloadHtml") {
|
||||
downloadHtml()
|
||||
}
|
||||
if (req.name == "360doc-downloadPdf") {
|
||||
downloadPdf()
|
||||
}
|
||||
})
|
||||
|
||||
function getDescription() {
|
||||
const summary = document.querySelector<HTMLMetaElement>(
|
||||
'meta[name="description"]'
|
||||
).content
|
||||
summary && prompt("文章摘要:", summary)
|
||||
}
|
||||
|
||||
function downloadPdf() {
|
||||
const article = document.querySelector<HTMLElement>("#bgchange")
|
||||
if (article) {
|
||||
Print.print(article, { title: articleTitle })
|
||||
.then(() => console.log("Printing complete"))
|
||||
.catch((error) => console.error("Printing failed:", error))
|
||||
}
|
||||
}
|
||||
|
||||
function editMarkdown() {
|
||||
const dom = document.querySelector("#bgchange")
|
||||
setContent(dom, articleTitle)
|
||||
}
|
||||
|
||||
function downloadMarkdown() {
|
||||
const html = document.querySelector("#bgchange")
|
||||
const markdown = turndownService.turndown(html)
|
||||
saveMarkdown(markdown, articleTitle)
|
||||
}
|
||||
|
||||
function downloadHtml() {
|
||||
const dom = document.querySelector("#bgchange")
|
||||
saveHtml(dom, articleTitle)
|
||||
}
|
||||
|
||||
function parseMarkdown() {
|
||||
const dom = document.querySelector("#bgchange")
|
||||
setParseContent(dom)
|
||||
}
|
||||
|
||||
return showTag && allShowTag ? (
|
||||
<ToolBox
|
||||
onGetDescription={getDescription}
|
||||
onEditMarkdown={editMarkdown}
|
||||
onDownloadMarkdown={downloadMarkdown}
|
||||
onPrint={downloadPdf}
|
||||
onParseMarkdown={parseMarkdown}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
}
|
||||
|
||||
export default PlasmoOverlay
|
||||
@@ -11,13 +11,9 @@ import { v4 as uuidv4 } from "uuid"
|
||||
import { useMessage } from "@plasmohq/messaging/hook"
|
||||
import { useStorage } from "@plasmohq/storage/hook"
|
||||
|
||||
import TagBtnStyle from "~component/tagBtn/style"
|
||||
import Tags from "~component/ui/tags"
|
||||
import { addCss, i18n, saveHtml, saveMarkdown } from "~tools"
|
||||
import useCssCodeHook from "~utils/cssCodeHook"
|
||||
import { useEditMarkdown } from "~utils/editMarkdownHook"
|
||||
import { useParseMarkdown } from "~utils/parseMarkdownHook"
|
||||
import { Print } from "~utils/print"
|
||||
import { useContent } from "~utils/editMarkdownHook"
|
||||
import Turndown from "~utils/turndown"
|
||||
|
||||
export const config: PlasmoCSConfig = {
|
||||
@@ -25,9 +21,7 @@ export const config: PlasmoCSConfig = {
|
||||
}
|
||||
|
||||
const turndownService = Turndown()
|
||||
const articleTitle = document
|
||||
.querySelector<HTMLElement>("head title")
|
||||
.innerText.trim()
|
||||
const articleTitle = document.querySelector<HTMLElement>("head title").innerText
|
||||
|
||||
const HOST_ID = "codebox-51cto"
|
||||
export const getShadowHostId: PlasmoGetShadowHostId = () => HOST_ID
|
||||
@@ -35,18 +29,35 @@ export const getShadowHostId: PlasmoGetShadowHostId = () => HOST_ID
|
||||
export const getOverlayAnchor: PlasmoGetOverlayAnchor = async () =>
|
||||
document.querySelector("article .title")
|
||||
|
||||
export const getStyle: PlasmoGetStyle = () => TagBtnStyle()
|
||||
export const getStyle: PlasmoGetStyle = () => {
|
||||
const style = document.createElement("style")
|
||||
style.textContent = `
|
||||
.codebox-tagBtn {
|
||||
height: 28px;
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
color: #1e80ff;
|
||||
width: 60px;
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
justify-content: space-between;
|
||||
padding: 0 8px;
|
||||
margin-top: -20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
`
|
||||
return style
|
||||
}
|
||||
|
||||
const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
const [parseContent, setParseContent] = useParseMarkdown()
|
||||
const [showTag, setShowTag] = useStorage<boolean>("51cto-showTag", true)
|
||||
const [allShowTag, setAllShowTag] = useStorage("config-allShowTag", true)
|
||||
const [showTag, setShowTag] = useStorage<boolean>("51cto-showTag")
|
||||
const [cssCode, runCss] = useCssCodeHook("51cto")
|
||||
const [copyCode] = useStorage<boolean>("51cto-copyCode")
|
||||
const [closeLoginModal] = useStorage<boolean>("51cto-closeLoginModal")
|
||||
const [history, setHistory] = useStorage<any[]>("codebox-history")
|
||||
const [closeLog] = useStorage("config-closeLog", true)
|
||||
const [content, setContent] = useEditMarkdown()
|
||||
const [content, setContent] = useContent()
|
||||
|
||||
useEffect(() => {
|
||||
closeLog || console.log("51CTO status", { closeLoginModal, copyCode })
|
||||
@@ -61,7 +72,7 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
res.send({ isShow: true })
|
||||
}
|
||||
if (req.name == "51cto-editMarkdown") {
|
||||
editMarkdown()
|
||||
setContent("article")
|
||||
}
|
||||
if (req.name == "51cto-downloadMarkdown") {
|
||||
downloadMarkdown()
|
||||
@@ -69,9 +80,6 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
if (req.name == "51cto-downloadHtml") {
|
||||
downloadHtml()
|
||||
}
|
||||
if (req.name == "51cto-downloadPdf") {
|
||||
downloadPdf()
|
||||
}
|
||||
})
|
||||
|
||||
/* 未登录复制代码 */
|
||||
@@ -221,43 +229,36 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
addCss(css)
|
||||
}
|
||||
|
||||
function downloadPdf() {
|
||||
var article = document.querySelector<HTMLElement>("article .article-detail")
|
||||
if (article) {
|
||||
Print.print(article, { title: articleTitle })
|
||||
.then(() => console.log("Printing complete"))
|
||||
.catch((error) => console.error("Printing failed:", error))
|
||||
}
|
||||
}
|
||||
|
||||
function downloadMarkdown() {
|
||||
const html = document.querySelector<HTMLElement>("article .article-detail")
|
||||
const html = document.querySelector("article")
|
||||
const markdown = turndownService.turndown(html)
|
||||
saveMarkdown(markdown, articleTitle)
|
||||
}
|
||||
|
||||
function downloadHtml() {
|
||||
const dom = document.querySelector<HTMLElement>("article .article-detail")
|
||||
const dom = document.querySelector("article")
|
||||
saveHtml(dom, articleTitle)
|
||||
}
|
||||
|
||||
function editMarkdown() {
|
||||
const dom = document.querySelector<HTMLElement>("article .article-detail")
|
||||
setContent(dom, articleTitle)
|
||||
function handleEdit() {
|
||||
setContent("article")
|
||||
}
|
||||
|
||||
function parseMarkdown() {
|
||||
const dom = document.querySelector<HTMLElement>("article .article-detail")
|
||||
setParseContent(dom)
|
||||
function handleDownload() {
|
||||
const html = document.querySelector("article")
|
||||
const markdown = turndownService.turndown(html)
|
||||
saveMarkdown(markdown, articleTitle)
|
||||
}
|
||||
|
||||
return showTag && allShowTag ? (
|
||||
<Tags
|
||||
onEdit={editMarkdown}
|
||||
onDownload={downloadMarkdown}
|
||||
onPrint={downloadPdf}
|
||||
onParse={parseMarkdown}
|
||||
/>
|
||||
function closeTag() {
|
||||
setShowTag(false)
|
||||
}
|
||||
|
||||
return showTag ? (
|
||||
<div className="codebox-tagBtn">
|
||||
<div onClick={handleEdit}>{i18n("edit")}</div>
|
||||
<div onClick={handleDownload}>{i18n("download")}</div>
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
|
||||
@@ -1,40 +1,26 @@
|
||||
import type {
|
||||
PlasmoCSConfig,
|
||||
PlasmoCSUIProps,
|
||||
PlasmoGetShadowHostId
|
||||
} from "plasmo"
|
||||
import { useEffect, useState, type FC } from "react"
|
||||
import type { PlasmoCSConfig } from "plasmo"
|
||||
import { useEffect } from "react"
|
||||
|
||||
import { useMessage } from "@plasmohq/messaging/hook"
|
||||
import { useStorage } from "@plasmohq/storage/hook"
|
||||
|
||||
import ToolBox from "~component/ui/toolBox"
|
||||
import { addCss, saveHtml, saveMarkdown } from "~tools"
|
||||
import useCssCodeHook from "~utils/cssCodeHook"
|
||||
import { useEditMarkdown } from "~utils/editMarkdownHook"
|
||||
import { useParseMarkdown } from "~utils/parseMarkdownHook"
|
||||
import { Print } from "~utils/print"
|
||||
import { useContent } from "~utils/editMarkdownHook"
|
||||
import Turndown from "~utils/turndown"
|
||||
|
||||
export const config: PlasmoCSConfig = {
|
||||
matches: ["https://baijiahao.baidu.com/*", "https://www.baidu.com/*"]
|
||||
matches: ["https://*.baidu.com/*"]
|
||||
}
|
||||
|
||||
const turndownService = Turndown()
|
||||
const articleTitle = document
|
||||
.querySelector<HTMLElement>("head title")
|
||||
.innerText.trim()
|
||||
const articleTitle = document.querySelector<HTMLElement>("head title").innerText
|
||||
|
||||
export const getShadowHostId: PlasmoGetShadowHostId = () => "codebox-baidu"
|
||||
const isBaijiahao = location.hostname.includes("baijiahao")
|
||||
const PlasmoOverlay: FC<PlasmoCSUIProps> = () => {
|
||||
const [parseContent, setParseContent] = useParseMarkdown()
|
||||
const [allShowTag, setAllShowTag] = useStorage("config-allShowTag", true)
|
||||
const [showTag, setShowTag] = useStorage<boolean>("baidu-showTag", true)
|
||||
export default function Custom() {
|
||||
const [cssCode, runCss] = useCssCodeHook("baidu")
|
||||
const [closeAIBox] = useStorage<boolean>("baidu-closeAIBox")
|
||||
const [closeLog] = useStorage("config-closeLog", true)
|
||||
const [content, setContent] = useEditMarkdown()
|
||||
const [content, setContent] = useContent()
|
||||
|
||||
useEffect(() => {
|
||||
closeLog || console.log("baidu", { closeAIBox })
|
||||
@@ -46,7 +32,7 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = () => {
|
||||
res.send({ isShow: true })
|
||||
}
|
||||
if (req.name == "baidu-editMarkdown") {
|
||||
editMarkdown()
|
||||
setContent(".wd-ai-index-pc")
|
||||
}
|
||||
if (req.name == "baidu-downloadMarkdown") {
|
||||
downloadMarkdown()
|
||||
@@ -63,64 +49,23 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = () => {
|
||||
}`)
|
||||
}
|
||||
|
||||
function getDescription() {
|
||||
const summary = document.querySelector<HTMLMetaElement>(
|
||||
'meta[name="description"]'
|
||||
).content
|
||||
summary && prompt("文章摘要:", summary)
|
||||
}
|
||||
|
||||
function downloadPdf() {
|
||||
const article = document.querySelector<HTMLElement>(
|
||||
isBaijiahao ? "#ssr-content .EaCvy" : ".wd-ai-index-pc"
|
||||
)
|
||||
if (article) {
|
||||
Print.print(article, { title: articleTitle })
|
||||
.then(() => console.log("Printing complete"))
|
||||
.catch((error) => console.error("Printing failed:", error))
|
||||
}
|
||||
}
|
||||
|
||||
function editMarkdown() {
|
||||
const dom = document.querySelector(
|
||||
isBaijiahao ? "#ssr-content .EaCvy" : ".wd-ai-index-pc"
|
||||
)
|
||||
setContent(dom, articleTitle)
|
||||
const html = document.querySelector("article.article")
|
||||
const markdown = turndownService.turndown(html)
|
||||
setContent(markdown)
|
||||
window.open("https://md.randbox.top", "_blank")
|
||||
}
|
||||
|
||||
function downloadMarkdown() {
|
||||
const html = document.querySelector(
|
||||
isBaijiahao ? "#ssr-content .EaCvy" : ".wd-ai-index-pc"
|
||||
)
|
||||
const html = document.querySelector(".wd-ai-index-pc")
|
||||
const markdown = turndownService.turndown(html)
|
||||
saveMarkdown(markdown, articleTitle)
|
||||
}
|
||||
|
||||
function downloadHtml() {
|
||||
const dom = document.querySelector(
|
||||
isBaijiahao ? "#ssr-content .EaCvy" : ".wd-ai-index-pc"
|
||||
)
|
||||
const dom = document.querySelector(".wd-ai-index-pc")
|
||||
saveHtml(dom, articleTitle)
|
||||
}
|
||||
|
||||
function parseMarkdown() {
|
||||
const dom = document.querySelector<HTMLElement>(
|
||||
isBaijiahao ? "#ssr-content .EaCvy" : ".wd-ai-index-pc"
|
||||
)
|
||||
setParseContent(dom)
|
||||
}
|
||||
|
||||
return showTag && allShowTag && isBaijiahao ? (
|
||||
<ToolBox
|
||||
onGetDescription={getDescription}
|
||||
onEditMarkdown={editMarkdown}
|
||||
onDownloadMarkdown={downloadMarkdown}
|
||||
onPrint={downloadPdf}
|
||||
onParseMarkdown={parseMarkdown}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
return <div style={{ display: "none" }}></div>
|
||||
}
|
||||
|
||||
export default PlasmoOverlay
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
import dayjs from "dayjs"
|
||||
import type { PlasmoCSConfig } from "plasmo"
|
||||
import React, { useEffect, useState } from "react"
|
||||
|
||||
import { Storage } from "@plasmohq/storage"
|
||||
import { useStorage } from "@plasmohq/storage/hook"
|
||||
|
||||
import QRCodeModal from "~component/ui/QRCodeModal"
|
||||
|
||||
export const config: PlasmoCSConfig = {
|
||||
matches: ["https://chatgpt.com/*", "https://chatgpt.com/c/*"]
|
||||
}
|
||||
|
||||
export default function Chatgpt() {
|
||||
const [validTime, setValidTime] = useStorage("ai-validTime", "1737872293")
|
||||
const [isModalOpen, setIsModalOpen] = useState(false)
|
||||
const [content, setContent] = useStorage({
|
||||
key: "ai-content",
|
||||
instance: new Storage({
|
||||
area: "local"
|
||||
})
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
let timer = null
|
||||
let index = 0
|
||||
if (content) {
|
||||
if (Number(validTime) < dayjs().unix()) {
|
||||
timer = setInterval(() => {
|
||||
const editorElement = document.querySelector(
|
||||
"._prosemirror-parent_cy42l_1 p"
|
||||
)
|
||||
index++
|
||||
if (editorElement && index < 30) {
|
||||
setIsModalOpen(true)
|
||||
clearTimeout(timer)
|
||||
} else if (index >= 30) {
|
||||
clearTimeout(timer)
|
||||
}
|
||||
}, 1000)
|
||||
} else {
|
||||
handleSetContent()
|
||||
}
|
||||
}
|
||||
return () => {
|
||||
clearTimeout(timer)
|
||||
}
|
||||
}, [content])
|
||||
|
||||
const handleCancelModal = () => {
|
||||
setContent("")
|
||||
setIsModalOpen(false)
|
||||
}
|
||||
|
||||
function handleConfirmModal() {
|
||||
let time = dayjs().add(1, "day").unix()
|
||||
|
||||
setValidTime(String(time))
|
||||
handleSetContent()
|
||||
setTimeout(() => {
|
||||
setIsModalOpen(false)
|
||||
}, 500)
|
||||
}
|
||||
|
||||
function handleSetContent() {
|
||||
const editorElement = document.querySelector(
|
||||
"._prosemirror-parent_cy42l_1 p"
|
||||
) as HTMLElement
|
||||
|
||||
if (editorElement) {
|
||||
editorElement.innerText = content
|
||||
|
||||
let index = 0
|
||||
const timer = setInterval(() => {
|
||||
const buttonElement = document.querySelector(
|
||||
"button[data-testid=send-button]"
|
||||
) as HTMLElement
|
||||
index++
|
||||
if (buttonElement && index < 30) {
|
||||
buttonElement.click()
|
||||
setContent("")
|
||||
clearTimeout(timer)
|
||||
} else if (index >= 30) {
|
||||
clearTimeout(timer)
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{isModalOpen && content && (
|
||||
<QRCodeModal
|
||||
onClose={handleCancelModal}
|
||||
onConfirm={handleConfirmModal}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,23 +1,13 @@
|
||||
import type {
|
||||
PlasmoCSConfig,
|
||||
PlasmoCSUIProps,
|
||||
PlasmoGetOverlayAnchor,
|
||||
PlasmoGetShadowHostId,
|
||||
PlasmoGetStyle
|
||||
} from "plasmo"
|
||||
import React, { useEffect, useRef, type FC } from "react"
|
||||
import type { PlasmoCSConfig } from "plasmo"
|
||||
import { useEffect, useRef } from "react"
|
||||
import { v4 as uuidv4 } from "uuid"
|
||||
|
||||
import { useMessage } from "@plasmohq/messaging/hook"
|
||||
import { useStorage } from "@plasmohq/storage/hook"
|
||||
|
||||
import TagBtnStyle from "~component/tagBtn/style"
|
||||
import ToolBox from "~component/ui/toolBox"
|
||||
import { saveHtml, saveMarkdown } from "~tools"
|
||||
import useCssCodeHook from "~utils/cssCodeHook"
|
||||
import { useEditMarkdown } from "~utils/editMarkdownHook"
|
||||
import { useParseMarkdown } from "~utils/parseMarkdownHook"
|
||||
import { Print } from "~utils/print"
|
||||
import { useContent } from "~utils/editMarkdownHook"
|
||||
import Turndown from "~utils/turndown"
|
||||
|
||||
export const config: PlasmoCSConfig = {
|
||||
@@ -26,27 +16,14 @@ export const config: PlasmoCSConfig = {
|
||||
}
|
||||
|
||||
const turndownService = Turndown()
|
||||
const articleTitle = document
|
||||
.querySelector<HTMLElement>("head title")
|
||||
.innerText.trim()
|
||||
const articleTitle = document.querySelector<HTMLElement>("head title").innerText
|
||||
|
||||
const HOST_ID = "codebox-cnblogs"
|
||||
export const getShadowHostId: PlasmoGetShadowHostId = () => HOST_ID
|
||||
|
||||
export const getOverlayAnchor: PlasmoGetOverlayAnchor = async () =>
|
||||
document.querySelector("#post_detail")
|
||||
|
||||
export const getStyle: PlasmoGetStyle = () => TagBtnStyle()
|
||||
|
||||
const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
const [parseContent, setParseContent] = useParseMarkdown()
|
||||
const [allShowTag, setAllShowTag] = useStorage("config-allShowTag", true)
|
||||
const [showTag, setShowTag] = useStorage<boolean>("cnblogs-showTag", true)
|
||||
export default function cnblogs() {
|
||||
const [cssCode, runCss] = useCssCodeHook("cnblogs")
|
||||
const [copyCode] = useStorage<boolean>("cnblogs-copyCode")
|
||||
const [history, setHistory] = useStorage<any[]>("codebox-history")
|
||||
const [closeLog] = useStorage("config-closeLog", true)
|
||||
const [content, setContent] = useEditMarkdown()
|
||||
const [content, setContent] = useContent()
|
||||
|
||||
useEffect(() => {
|
||||
closeLog || console.log("cnblogs copyCode", copyCode)
|
||||
@@ -58,7 +35,7 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
res.send({ isShow: true })
|
||||
}
|
||||
if (req.name == "cnblogs-editMarkdown") {
|
||||
editMarkdown()
|
||||
setContent("article.article")
|
||||
}
|
||||
if (req.name == "cnblogs-downloadMarkdown") {
|
||||
downloadMarkdown()
|
||||
@@ -66,9 +43,6 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
if (req.name == "cnblogs-downloadHtml") {
|
||||
downloadHtml()
|
||||
}
|
||||
if (req.name == "cnblogs-downloadPdf") {
|
||||
downloadPdf()
|
||||
}
|
||||
})
|
||||
|
||||
// 功能一: 修改复制按钮,支持一键复制
|
||||
@@ -145,54 +119,16 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
})
|
||||
}
|
||||
|
||||
function getDescription() {
|
||||
const summary = document.querySelector<HTMLMetaElement>(
|
||||
'meta[name="description"]'
|
||||
).content
|
||||
summary && prompt("文章摘要:", summary)
|
||||
}
|
||||
|
||||
function downloadPdf() {
|
||||
const article = document.querySelector<HTMLElement>("#post_detail .post")
|
||||
if (article) {
|
||||
Print.print(article, { title: articleTitle })
|
||||
.then(() => console.log("Printing complete"))
|
||||
.catch((error) => console.error("Printing failed:", error))
|
||||
}
|
||||
}
|
||||
|
||||
function editMarkdown() {
|
||||
const dom = document.querySelector<HTMLElement>("#post_detail")
|
||||
setContent(dom, articleTitle)
|
||||
}
|
||||
|
||||
function downloadMarkdown() {
|
||||
const html = document.querySelector<HTMLElement>("#post_detail")
|
||||
const html = document.querySelector("#post_detail")
|
||||
const markdown = turndownService.turndown(html)
|
||||
saveMarkdown(markdown, articleTitle)
|
||||
}
|
||||
|
||||
function downloadHtml() {
|
||||
const dom = document.querySelector("#post_detail .post")
|
||||
const dom = document.querySelector("#post_detail")
|
||||
saveHtml(dom, articleTitle)
|
||||
}
|
||||
|
||||
function parseMarkdown() {
|
||||
const dom = document.querySelector<HTMLElement>("#post_detail")
|
||||
setParseContent(dom)
|
||||
}
|
||||
|
||||
return showTag && allShowTag ? (
|
||||
<ToolBox
|
||||
onGetDescription={getDescription}
|
||||
onEditMarkdown={editMarkdown}
|
||||
onDownloadMarkdown={downloadMarkdown}
|
||||
onPrint={downloadPdf}
|
||||
onParseMarkdown={parseMarkdown}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
return <div style={{ display: "none" }}></div>
|
||||
}
|
||||
|
||||
export default PlasmoOverlay
|
||||
|
||||
@@ -19,10 +19,10 @@ export const config: PlasmoCSConfig = {
|
||||
matches: [
|
||||
"https://*.npmjs.com/*",
|
||||
"https://*.medium.com/*",
|
||||
"https://mp.weixin.qq.com/*",
|
||||
"https://day.js.org/*",
|
||||
"https://stackoverflow.com/*",
|
||||
"https://dev.to/*",
|
||||
"https://greasyfork.org/*"
|
||||
"https://dev.to/*"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -70,12 +70,7 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
|
||||
const element = anchor.element
|
||||
const style = window.getComputedStyle(element)
|
||||
let width = style.getPropertyValue("width")
|
||||
|
||||
if (location.host.includes("greasyfork")) {
|
||||
const codeContainer = element.closest(".code-container")
|
||||
width = window.getComputedStyle(codeContainer).getPropertyValue("width")
|
||||
}
|
||||
const width = style.getPropertyValue("width")
|
||||
|
||||
const onCopy = async () => {
|
||||
try {
|
||||
@@ -85,9 +80,9 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
let textContent = ""
|
||||
|
||||
if (codeBlock) {
|
||||
textContent = codeBlock.innerText
|
||||
textContent = codeBlock.textContent
|
||||
} else {
|
||||
textContent = preBlock && preBlock.innerText
|
||||
textContent = preBlock && preBlock.textContent
|
||||
}
|
||||
|
||||
navigator.clipboard.writeText(textContent)
|
||||
|
||||
@@ -11,13 +11,9 @@ import { v4 as uuidv4 } from "uuid"
|
||||
import { useMessage } from "@plasmohq/messaging/hook"
|
||||
import { useStorage } from "@plasmohq/storage/hook"
|
||||
|
||||
import TagBtnStyle from "~component/tagBtn/style"
|
||||
import Tags from "~component/ui/tags"
|
||||
import { addCss, i18n, saveHtml, saveMarkdown } from "~tools"
|
||||
import useCssCodeHook from "~utils/cssCodeHook"
|
||||
import { useEditMarkdown } from "~utils/editMarkdownHook"
|
||||
import { useParseMarkdown } from "~utils/parseMarkdownHook"
|
||||
import { Print } from "~utils/print"
|
||||
import { useContent } from "~utils/editMarkdownHook"
|
||||
import Turndown from "~utils/turndown"
|
||||
|
||||
export const config: PlasmoCSConfig = {
|
||||
@@ -34,12 +30,29 @@ export const getOverlayAnchor: PlasmoGetOverlayAnchor = async () =>
|
||||
document.querySelector(".blog-content-box .title-article") ||
|
||||
document.querySelector(".article-detail .title")
|
||||
|
||||
export const getStyle: PlasmoGetStyle = () => TagBtnStyle()
|
||||
export const getStyle: PlasmoGetStyle = () => {
|
||||
const style = document.createElement("style")
|
||||
style.textContent = `
|
||||
.codebox-tagBtn {
|
||||
height: 28px;
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
color: #1e80ff;
|
||||
width: 60px;
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
justify-content: space-between;
|
||||
padding: 0 8px;
|
||||
margin-top: -20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
`
|
||||
return style
|
||||
}
|
||||
|
||||
const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
const [parseContent, setParseContent] = useParseMarkdown()
|
||||
const [allShowTag, setAllShowTag] = useStorage("config-allShowTag", true)
|
||||
const [showTag, setShowTag] = useStorage<boolean>("csdn-showTag", true)
|
||||
const [showTag, setShowTag] = useStorage<boolean>("csdn-showTag")
|
||||
const [cssCode, runCss] = useCssCodeHook("csdn")
|
||||
const [closeAds] = useStorage<boolean>("csdn-closeAds")
|
||||
const [copyCode] = useStorage<boolean>("csdn-copyCode")
|
||||
@@ -50,7 +63,7 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
const [closeRedirectModal] = useStorage<boolean>("csdn-closeLoginModal")
|
||||
const [history, setHistory] = useStorage<any[]>("codebox-history")
|
||||
const [closeLog] = useStorage("config-closeLog", true)
|
||||
const [content, setContent] = useEditMarkdown()
|
||||
const [content, setContent] = useContent()
|
||||
|
||||
useEffect(() => {
|
||||
closeLog ||
|
||||
@@ -85,7 +98,7 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
res.send({ isShow: true })
|
||||
}
|
||||
if (req.name == "csdn-editMarkdown") {
|
||||
editMarkdown()
|
||||
setContent(".blog-content-box")
|
||||
}
|
||||
if (req.name == "csdn-downloadMarkdown") {
|
||||
downloadMarkdown()
|
||||
@@ -93,9 +106,6 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
if (req.name == "csdn-downloadHtml") {
|
||||
downloadHtml()
|
||||
}
|
||||
if (req.name == "csdn-downloadPdf") {
|
||||
downloadPdf()
|
||||
}
|
||||
})
|
||||
|
||||
/* 未登录复制代码 */
|
||||
@@ -270,20 +280,6 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
})
|
||||
}
|
||||
|
||||
function downloadPdf() {
|
||||
const article = document.querySelector<HTMLElement>(".blog-content-box")
|
||||
if (article) {
|
||||
Print.print(article, { title: articleTitle })
|
||||
.then(() => console.log("Printing complete"))
|
||||
.catch((error) => console.error("Printing failed:", error))
|
||||
}
|
||||
}
|
||||
|
||||
function editMarkdown() {
|
||||
const dom = document.querySelector(".blog-content-box")
|
||||
setContent(dom, articleTitle)
|
||||
}
|
||||
|
||||
function downloadMarkdown() {
|
||||
const html = document.querySelector(".blog-content-box")
|
||||
const markdown = turndownService.turndown(html)
|
||||
@@ -295,18 +291,25 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
saveHtml(dom, articleTitle)
|
||||
}
|
||||
|
||||
function parseMarkdown() {
|
||||
const dom = document.querySelector(".blog-content-box")
|
||||
setParseContent(dom)
|
||||
function handleEdit() {
|
||||
setContent(".blog-content-box")
|
||||
}
|
||||
|
||||
return showTag && allShowTag ? (
|
||||
<Tags
|
||||
onEdit={editMarkdown}
|
||||
onDownload={downloadMarkdown}
|
||||
onPrint={downloadPdf}
|
||||
onParse={parseMarkdown}
|
||||
/>
|
||||
function handleDownload() {
|
||||
const html = document.querySelector(".blog-content-box")
|
||||
const markdown = turndownService.turndown(html)
|
||||
saveMarkdown(markdown, articleTitle)
|
||||
}
|
||||
|
||||
function closeTag() {
|
||||
setShowTag(false)
|
||||
}
|
||||
|
||||
return showTag ? (
|
||||
<div className="codebox-tagBtn">
|
||||
<div onClick={handleEdit}>{i18n("edit")}</div>
|
||||
<div onClick={handleDownload}>{i18n("download")}</div>
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
import { StyleProvider } from "@ant-design/cssinjs"
|
||||
import {
|
||||
CheckOutlined,
|
||||
CloseOutlined,
|
||||
DownSquareOutlined,
|
||||
LeftSquareOutlined,
|
||||
RightSquareOutlined,
|
||||
UpSquareOutlined
|
||||
} from "@ant-design/icons"
|
||||
import { Button, Flex, message, Modal } from "antd"
|
||||
import antdResetCssText from "data-text:antd/dist/reset.css"
|
||||
import dayjs from "dayjs"
|
||||
import type {
|
||||
PlasmoCSConfig,
|
||||
PlasmoGetShadowHostId,
|
||||
@@ -9,95 +21,339 @@ import { sendToBackground } from "@plasmohq/messaging"
|
||||
import { useMessage } from "@plasmohq/messaging/hook"
|
||||
import { useStorage } from "@plasmohq/storage/hook"
|
||||
|
||||
import CustomDomSelector from "~component/ui/customDomSelector"
|
||||
import { setIcon } from "~tools"
|
||||
import { getSummary } from "~utils/coze"
|
||||
import ValidateContent from "~component/contents/validateContent"
|
||||
import { ThemeProvider } from "~theme"
|
||||
import { addCss, saveHtml, saveMarkdown, scrollToTop, setIcon } from "~tools"
|
||||
import useCssCodeHook from "~utils/cssCodeHook"
|
||||
import DrawImages from "~utils/drawImages"
|
||||
import makerQRPost from "~utils/makerQRPost"
|
||||
import { useContent } from "~utils/editMarkdownHook"
|
||||
import Turndown from "~utils/turndown"
|
||||
|
||||
const turndownService = Turndown()
|
||||
const articleTitle =
|
||||
document.querySelector<HTMLElement>("head title")?.innerText
|
||||
|
||||
const HOST_ID = "codebox-csui"
|
||||
|
||||
export const getShadowHostId: PlasmoGetShadowHostId = () => HOST_ID
|
||||
|
||||
const articleTitle = document
|
||||
.querySelector<HTMLElement>("head title")
|
||||
?.innerText.trim()
|
||||
export const getStyle: PlasmoGetStyle = () => {
|
||||
const style = document.createElement("style")
|
||||
|
||||
style.textContent = antdResetCssText
|
||||
return style
|
||||
}
|
||||
|
||||
let isDownloadType = "markdown"
|
||||
let isReady = false
|
||||
let isSelect = false
|
||||
|
||||
export default function CustomOverlay() {
|
||||
const [summary, setSummary] = useStorage("app-summary", "")
|
||||
const [cssCode, runCss] = useCssCodeHook("custom")
|
||||
const [content, setContent] = useContent()
|
||||
const [validTime, setValidTime] = useStorage("app-validTime", "1730390400")
|
||||
const [isCurrentDom, setIsCurrentDom] = useState<boolean>(false)
|
||||
const [rect, setRect] = useState<any>(() => {
|
||||
return { top: 0, right: 0 }
|
||||
})
|
||||
const [messageApi, contextHolder] = message.useMessage()
|
||||
|
||||
useEffect(() => {
|
||||
setIcon(true)
|
||||
getSelection()
|
||||
|
||||
const hostname = location.hostname
|
||||
setIcon(
|
||||
hostname.includes("csdn") ||
|
||||
hostname.includes("zhihu") ||
|
||||
hostname.includes("baidu") ||
|
||||
hostname.includes("jianshu") ||
|
||||
hostname.includes("jb51") ||
|
||||
hostname.includes("cnblogs") ||
|
||||
hostname.includes("51cto") ||
|
||||
hostname.includes("juejin") ||
|
||||
hostname.includes("php") ||
|
||||
hostname.includes("oschina") ||
|
||||
hostname.includes("segmentfault") ||
|
||||
hostname.includes("weixin") ||
|
||||
hostname.includes("medium")
|
||||
)
|
||||
}, [])
|
||||
|
||||
useMessage(async (req: any, res: any) => {
|
||||
if (req.name == "app-downloadImages") {
|
||||
await downloadImages(req.body?.onProgress)
|
||||
useMessage(async (req, res) => {
|
||||
if (req.name == "custom-isShow") {
|
||||
res.send({ isShow: true })
|
||||
}
|
||||
if (req.name == "app-get-summary") {
|
||||
setSummary("")
|
||||
const res = await getSummary(location.href)
|
||||
if (res.code == 0) {
|
||||
const result = JSON.parse(res.data)
|
||||
setSummary(result)
|
||||
}
|
||||
if (req.name == "custom-downloadHtml") {
|
||||
setCustom("html")
|
||||
}
|
||||
if (req.name == "app-makerQRPost") {
|
||||
makerQRPost()
|
||||
if (req.name == "custom-downloadMarkdown") {
|
||||
setCustom("downloadMarkdown")
|
||||
}
|
||||
if (req.name == "app-getArticle") {
|
||||
const href = encodeURIComponent(location.href)
|
||||
window.open(`https://paywallbuster.com/articles/?article=${href}`)
|
||||
if (req.name == "custom-downloadPdf") {
|
||||
setCustom("pdf")
|
||||
}
|
||||
if (req.name == "custom-downloadImg") {
|
||||
setCustom("img")
|
||||
}
|
||||
if (req.name == "custom-editMarkdown") {
|
||||
setCustom("editMarkdown")
|
||||
}
|
||||
if (req.name == "app-full-page-screenshot") {
|
||||
if (confirm("确认截图?")) {
|
||||
const { scrollHeight, clientHeight } = document.documentElement
|
||||
const devicePixelRatio = window.devicePixelRatio || 1
|
||||
const { scrollHeight, clientHeight } = document.documentElement
|
||||
const devicePixelRatio = window.devicePixelRatio || 1
|
||||
|
||||
let capturedHeight = 0
|
||||
let capturedImages = []
|
||||
let capturedHeight = 0
|
||||
let capturedImages = []
|
||||
|
||||
const captureAndScroll = async () => {
|
||||
const scrollAmount = clientHeight * devicePixelRatio
|
||||
const res = await sendToBackground({ name: "screenshot" })
|
||||
const dataUrl = res.dataUrl
|
||||
const captureAndScroll = async () => {
|
||||
const scrollAmount = clientHeight * devicePixelRatio
|
||||
const res = await sendToBackground({ name: "screenshot" })
|
||||
const dataUrl = res.dataUrl
|
||||
|
||||
capturedHeight += scrollAmount
|
||||
if (capturedHeight < scrollHeight * devicePixelRatio) {
|
||||
capturedImages.push(dataUrl)
|
||||
window.scrollTo(0, capturedHeight)
|
||||
setTimeout(captureAndScroll, 2000) // Adjust the delay as needed
|
||||
} else {
|
||||
DrawImages(capturedImages, articleTitle)
|
||||
}
|
||||
capturedHeight += scrollAmount
|
||||
if (capturedHeight < scrollHeight * devicePixelRatio) {
|
||||
capturedImages.push(dataUrl)
|
||||
window.scrollTo(0, capturedHeight)
|
||||
setTimeout(captureAndScroll, 2000) // Adjust the delay as needed
|
||||
} else {
|
||||
DrawImages(capturedImages, articleTitle)
|
||||
}
|
||||
|
||||
captureAndScroll()
|
||||
}
|
||||
|
||||
captureAndScroll()
|
||||
}
|
||||
})
|
||||
|
||||
async function downloadImages(
|
||||
onProgress?: (current: number, total: number) => void
|
||||
) {
|
||||
const imageUrls = Array.from(document.images).map((img) => img.src)
|
||||
try {
|
||||
const res = await sendToBackground({
|
||||
name: "download",
|
||||
body: {
|
||||
action: "downloadAllImages",
|
||||
imageUrls: imageUrls,
|
||||
title: articleTitle,
|
||||
onProgress: onProgress
|
||||
}
|
||||
})
|
||||
if (res.code == 0) {
|
||||
alert("下载失败")
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Failed to download images:`, error)
|
||||
}
|
||||
function setCustom(type) {
|
||||
isReady = true
|
||||
isSelect = false
|
||||
isDownloadType = type
|
||||
messageApi.info("请在页面选择要下载区域!")
|
||||
}
|
||||
|
||||
return <CustomDomSelector />
|
||||
function getSelection() {
|
||||
addCss(`.codebox-current { border: 1px solid #7983ff!important; }`)
|
||||
document.addEventListener("mousemove", (event) => {
|
||||
const target = event.target as HTMLElement
|
||||
if (isReady && target && !isSelect) {
|
||||
removeCurrentDom()
|
||||
target.classList.add("codebox-current")
|
||||
}
|
||||
})
|
||||
document.addEventListener("click", (event) => {
|
||||
const target = event.target as HTMLElement
|
||||
const tooltip = target.closest("#codebox-csui")
|
||||
const modal = target.closest(".ant-modal")
|
||||
const submit = target.closest(".valid-submit")
|
||||
|
||||
if (isReady && target && !tooltip && !modal && !submit) {
|
||||
isSelect = true
|
||||
setIsCurrentDom(true)
|
||||
removeCurrentDom()
|
||||
target.classList.add("codebox-current")
|
||||
setTooltip()
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function setTooltip() {
|
||||
const currentDom = document.querySelector<HTMLElement>(".codebox-current")
|
||||
const rect = currentDom.getBoundingClientRect()
|
||||
const distanceTop = rect.top + window.scrollY
|
||||
const distanceLeft = rect.left + window.scrollX
|
||||
const top = distanceTop < 50 ? distanceTop + 15 : distanceTop - 40
|
||||
const left = distanceLeft + 5
|
||||
|
||||
setRect({ top, left })
|
||||
scrollToTop(currentDom)
|
||||
}
|
||||
|
||||
function removeCurrentDom() {
|
||||
const currentList = document.querySelectorAll(".codebox-current")
|
||||
currentList.forEach((el) => {
|
||||
el.classList.remove("codebox-current")
|
||||
})
|
||||
}
|
||||
|
||||
function downloadHtml(currentDom) {
|
||||
saveHtml(currentDom, articleTitle)
|
||||
}
|
||||
|
||||
function downloadMarkdown(currentDom) {
|
||||
const markdown = turndownService.turndown(currentDom)
|
||||
saveMarkdown(markdown, articleTitle)
|
||||
}
|
||||
|
||||
function handleOk() {
|
||||
const currentDom = document.querySelector(".codebox-current")
|
||||
|
||||
if (isDownloadType == "html") {
|
||||
removeCurrentDom()
|
||||
downloadHtml(currentDom)
|
||||
} else if (isDownloadType == "downloadMarkdown") {
|
||||
removeCurrentDom()
|
||||
downloadMarkdown(currentDom)
|
||||
} else if (isDownloadType == "editMarkdown") {
|
||||
setContent(".codebox-current")
|
||||
removeCurrentDom()
|
||||
}
|
||||
isReady = false
|
||||
isSelect = false
|
||||
setIsCurrentDom(false)
|
||||
}
|
||||
|
||||
function handleConfirm() {
|
||||
Modal.confirm({
|
||||
title: "提示",
|
||||
content: (
|
||||
<>
|
||||
<div style={{ fontSize: "18px" }}>是否保存?</div>
|
||||
{Number(validTime) > dayjs().unix() ? (
|
||||
<></>
|
||||
) : (
|
||||
<ValidateContent></ValidateContent>
|
||||
)}
|
||||
</>
|
||||
),
|
||||
okText: "确认",
|
||||
okButtonProps: {
|
||||
// disabled: Number(validTime) <= dayjs().unix()
|
||||
},
|
||||
onOk: () => {
|
||||
handleOk()
|
||||
},
|
||||
cancelText: "取消",
|
||||
onCancel: () => {
|
||||
handleCancel()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function handleCancel() {
|
||||
removeCurrentDom()
|
||||
isReady = false
|
||||
isSelect = false
|
||||
setIsCurrentDom(false)
|
||||
}
|
||||
|
||||
function handleSetParent(event) {
|
||||
const currentDom = document.querySelector(".codebox-current")
|
||||
const parent = currentDom.parentElement
|
||||
|
||||
if (parent) {
|
||||
removeCurrentDom()
|
||||
parent.classList.add("codebox-current")
|
||||
setTooltip()
|
||||
}
|
||||
event.stopPropagation()
|
||||
}
|
||||
|
||||
function handleSetChild(event) {
|
||||
const currentDom = document.querySelector(".codebox-current")
|
||||
const child = currentDom.firstElementChild
|
||||
if (child) {
|
||||
removeCurrentDom()
|
||||
child.classList.add("codebox-current")
|
||||
setTooltip()
|
||||
}
|
||||
event.stopPropagation()
|
||||
}
|
||||
|
||||
function handleSetPrev(event) {
|
||||
const currentDom = document.querySelector(".codebox-current")
|
||||
const previousSibling = currentDom.previousElementSibling
|
||||
if (previousSibling) {
|
||||
removeCurrentDom()
|
||||
previousSibling.classList.add("codebox-current")
|
||||
setTooltip()
|
||||
}
|
||||
event.stopPropagation()
|
||||
}
|
||||
|
||||
function handleSetNext(event) {
|
||||
const currentDom = document.querySelector(".codebox-current")
|
||||
const nextSibling = currentDom.nextElementSibling
|
||||
if (nextSibling) {
|
||||
removeCurrentDom()
|
||||
nextSibling.classList.add("codebox-current")
|
||||
setTooltip()
|
||||
}
|
||||
event.stopPropagation()
|
||||
}
|
||||
|
||||
return (
|
||||
<ThemeProvider>
|
||||
{contextHolder}
|
||||
<StyleProvider container={document.getElementById(HOST_ID).shadowRoot}>
|
||||
{isCurrentDom ? (
|
||||
<div
|
||||
className="codebox-tooltip"
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: `${rect.top}px`,
|
||||
left: `${rect.left}px`,
|
||||
width: "520px",
|
||||
background: "#fff",
|
||||
border: "1px solid #eee",
|
||||
borderRadius: "5px"
|
||||
}}>
|
||||
<Flex wrap gap="small">
|
||||
<Button
|
||||
color="primary"
|
||||
variant="text"
|
||||
size="small"
|
||||
icon={<CheckOutlined />}
|
||||
onClick={handleConfirm}>
|
||||
确定
|
||||
</Button>
|
||||
<Button
|
||||
color="default"
|
||||
variant="text"
|
||||
size="small"
|
||||
icon={<UpSquareOutlined />}
|
||||
onClick={handleSetParent}>
|
||||
父节点
|
||||
</Button>
|
||||
<Button
|
||||
color="default"
|
||||
variant="text"
|
||||
size="small"
|
||||
icon={<DownSquareOutlined />}
|
||||
onClick={handleSetChild}>
|
||||
子节点
|
||||
</Button>
|
||||
<Button
|
||||
color="default"
|
||||
variant="text"
|
||||
size="small"
|
||||
icon={<LeftSquareOutlined />}
|
||||
onClick={handleSetPrev}>
|
||||
上一个
|
||||
</Button>
|
||||
<Button
|
||||
color="default"
|
||||
variant="text"
|
||||
size="small"
|
||||
icon={<RightSquareOutlined />}
|
||||
onClick={handleSetNext}>
|
||||
下一个
|
||||
</Button>
|
||||
<Button
|
||||
color="danger"
|
||||
variant="text"
|
||||
size="small"
|
||||
icon={<CloseOutlined />}
|
||||
onClick={handleCancel}>
|
||||
取消
|
||||
</Button>
|
||||
</Flex>
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</StyleProvider>
|
||||
</ThemeProvider>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
import dayjs from "dayjs"
|
||||
import type { PlasmoCSConfig } from "plasmo"
|
||||
import React, { useEffect, useState } from "react"
|
||||
|
||||
import { Storage } from "@plasmohq/storage"
|
||||
import { useStorage } from "@plasmohq/storage/hook"
|
||||
|
||||
import QRCodeModal from "~component/ui/QRCodeModal"
|
||||
|
||||
export const config: PlasmoCSConfig = {
|
||||
matches: ["https://chat.deepseek.com/*"]
|
||||
}
|
||||
|
||||
export default function Deepseek() {
|
||||
const [validTime, setValidTime] = useStorage("ai-validTime", "1737872293")
|
||||
const [isModalOpen, setIsModalOpen] = useState(false)
|
||||
const [content, setContent] = useStorage({
|
||||
key: "ai-content",
|
||||
instance: new Storage({
|
||||
area: "local"
|
||||
})
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
let timer = null
|
||||
let index = 0
|
||||
if (content) {
|
||||
if (Number(validTime) < dayjs().unix()) {
|
||||
timer = setInterval(() => {
|
||||
const editorElement = document.querySelector(
|
||||
"#chat-input"
|
||||
) as HTMLElement
|
||||
index++
|
||||
if (editorElement && index < 30) {
|
||||
setIsModalOpen(true)
|
||||
clearTimeout(timer)
|
||||
} else if (index >= 30) {
|
||||
clearTimeout(timer)
|
||||
}
|
||||
}, 1000)
|
||||
} else {
|
||||
handleSetContent()
|
||||
}
|
||||
}
|
||||
return () => {
|
||||
clearTimeout(timer)
|
||||
}
|
||||
}, [content, validTime])
|
||||
|
||||
const handleCancelModal = () => {
|
||||
setContent("")
|
||||
setIsModalOpen(false)
|
||||
}
|
||||
|
||||
function handleConfirmModal() {
|
||||
let time = dayjs().add(1, "day").unix()
|
||||
|
||||
setValidTime(String(time))
|
||||
handleSetContent()
|
||||
setTimeout(() => {
|
||||
setIsModalOpen(false)
|
||||
}, 500)
|
||||
}
|
||||
|
||||
function handleSetContent() {
|
||||
const editorElement = document.querySelector(
|
||||
"#chat-input"
|
||||
) as HTMLInputElement
|
||||
|
||||
const buttonElement = document.querySelector(".f6d670") as HTMLElement
|
||||
|
||||
if (editorElement) {
|
||||
editorElement.value = content
|
||||
editorElement.dispatchEvent(new Event("input", { bubbles: true }))
|
||||
editorElement.dispatchEvent(new Event("change", { bubbles: true }))
|
||||
editorElement.focus()
|
||||
editorElement.setSelectionRange(
|
||||
editorElement.value.length,
|
||||
editorElement.value.length
|
||||
)
|
||||
document.execCommand("InsertText", false, content)
|
||||
|
||||
setContent("")
|
||||
|
||||
setTimeout(() => {
|
||||
buttonElement.click()
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{isModalOpen && content && (
|
||||
<QRCodeModal
|
||||
onClose={handleCancelModal}
|
||||
onConfirm={handleConfirmModal}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,22 +1,13 @@
|
||||
import type {
|
||||
PlasmoCSConfig,
|
||||
PlasmoCSUIProps,
|
||||
PlasmoGetOverlayAnchor,
|
||||
PlasmoGetShadowHostId,
|
||||
PlasmoGetStyle
|
||||
} from "plasmo"
|
||||
import React, { useEffect, type FC } from "react"
|
||||
import type { PlasmoCSConfig } from "plasmo"
|
||||
import { useEffect } from "react"
|
||||
import { v4 as uuidv4 } from "uuid"
|
||||
|
||||
import { useMessage } from "@plasmohq/messaging/hook"
|
||||
import { useStorage } from "@plasmohq/storage/hook"
|
||||
|
||||
import ToolBox from "~component/ui/toolBox"
|
||||
import { addCss, saveHtml, saveMarkdown } from "~tools"
|
||||
import useCssCodeHook from "~utils/cssCodeHook"
|
||||
import { useEditMarkdown } from "~utils/editMarkdownHook"
|
||||
import { useParseMarkdown } from "~utils/parseMarkdownHook"
|
||||
import { Print } from "~utils/print"
|
||||
import { useContent } from "~utils/editMarkdownHook"
|
||||
import Turndown from "~utils/turndown"
|
||||
|
||||
export const config: PlasmoCSConfig = {
|
||||
@@ -24,26 +15,15 @@ export const config: PlasmoCSConfig = {
|
||||
}
|
||||
|
||||
const turndownService = Turndown()
|
||||
const articleTitle = document
|
||||
.querySelector<HTMLElement>("head title")
|
||||
.innerText.trim()
|
||||
const articleTitle = document.querySelector<HTMLElement>("head title").innerText
|
||||
|
||||
const HOST_ID = "codebox-jb51"
|
||||
export const getShadowHostId: PlasmoGetShadowHostId = () => HOST_ID
|
||||
|
||||
export const getOverlayAnchor: PlasmoGetOverlayAnchor = async () =>
|
||||
document.querySelector("#article .title")
|
||||
|
||||
const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
const [parseContent, setParseContent] = useParseMarkdown()
|
||||
const [allShowTag, setAllShowTag] = useStorage("config-allShowTag", true)
|
||||
const [showTag, setShowTag] = useStorage<boolean>("jb51-showTag", true)
|
||||
export default function jb51() {
|
||||
const [cssCode, runCss] = useCssCodeHook("jb51")
|
||||
const [closeAds] = useStorage<boolean>("jb51-closeAds")
|
||||
const [copyCode] = useStorage<boolean>("jb51-copyCode")
|
||||
const [history, setHistory] = useStorage<any[]>("codebox-history")
|
||||
const [closeLog] = useStorage("config-closeLog", true)
|
||||
const [content, setEditMarkdown] = useEditMarkdown()
|
||||
const [content, setContent] = useContent()
|
||||
|
||||
useEffect(() => {
|
||||
closeLog || console.log("jb51 status", { closeAds, copyCode })
|
||||
@@ -56,7 +36,7 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
res.send({ isShow: true })
|
||||
}
|
||||
if (req.name == "jb51-editMarkdown") {
|
||||
editMarkdown()
|
||||
setContent("#article")
|
||||
}
|
||||
if (req.name == "jb51-downloadMarkdown") {
|
||||
downloadMarkdown()
|
||||
@@ -64,9 +44,6 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
if (req.name == "jb51-downloadHtml") {
|
||||
downloadHtml()
|
||||
}
|
||||
if (req.name == "jb51-downloadPdf") {
|
||||
downloadPdf()
|
||||
}
|
||||
})
|
||||
|
||||
/* 未登录复制代码 */
|
||||
@@ -222,27 +199,6 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
}`)
|
||||
}
|
||||
|
||||
function getDescription() {
|
||||
const summary = document.querySelector<HTMLMetaElement>(
|
||||
'meta[name="description"]'
|
||||
).content
|
||||
summary && prompt("文章摘要:", summary)
|
||||
}
|
||||
|
||||
function downloadPdf() {
|
||||
const article = document.querySelector<HTMLElement>("#article")
|
||||
if (article) {
|
||||
Print.print(article, { title: articleTitle })
|
||||
.then(() => console.log("Printing complete"))
|
||||
.catch((error) => console.error("Printing failed:", error))
|
||||
}
|
||||
}
|
||||
|
||||
function editMarkdown() {
|
||||
const dom = document.querySelector("#article")
|
||||
setEditMarkdown(dom, articleTitle)
|
||||
}
|
||||
|
||||
function downloadMarkdown() {
|
||||
const html = document.querySelector("#article")
|
||||
const markdown = turndownService.turndown(html)
|
||||
@@ -254,22 +210,5 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
saveHtml(dom, articleTitle)
|
||||
}
|
||||
|
||||
function parseMarkdown() {
|
||||
const dom = document.querySelector<HTMLElement>("#article")
|
||||
setParseContent(dom)
|
||||
}
|
||||
|
||||
return showTag && allShowTag ? (
|
||||
<ToolBox
|
||||
onGetDescription={getDescription}
|
||||
onEditMarkdown={editMarkdown}
|
||||
onDownloadMarkdown={downloadMarkdown}
|
||||
onPrint={downloadPdf}
|
||||
onParseMarkdown={parseMarkdown}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
return <div style={{ display: "none" }}></div>
|
||||
}
|
||||
|
||||
export default PlasmoOverlay
|
||||
|
||||
@@ -1,24 +1,13 @@
|
||||
import type {
|
||||
PlasmoCSConfig,
|
||||
PlasmoCSUIProps,
|
||||
PlasmoGetOverlayAnchor,
|
||||
PlasmoGetShadowHostId,
|
||||
PlasmoGetStyle
|
||||
} from "plasmo"
|
||||
import React, { useEffect, useRef, type FC } from "react"
|
||||
import type { PlasmoCSConfig } from "plasmo"
|
||||
import { useEffect, useRef } from "react"
|
||||
import { v4 as uuidv4 } from "uuid"
|
||||
|
||||
import { useMessage } from "@plasmohq/messaging/hook"
|
||||
import { useStorage } from "@plasmohq/storage/hook"
|
||||
|
||||
import TagBtnStyle from "~component/tagBtn/style"
|
||||
import Tags from "~component/ui/tags"
|
||||
import ToolBox from "~component/ui/toolBox"
|
||||
import { addCss, i18n, saveHtml, saveMarkdown } from "~tools"
|
||||
import { addCss, saveHtml, saveMarkdown } from "~tools"
|
||||
import useCssCodeHook from "~utils/cssCodeHook"
|
||||
import { useEditMarkdown } from "~utils/editMarkdownHook"
|
||||
import { useParseMarkdown } from "~utils/parseMarkdownHook"
|
||||
import { Print } from "~utils/print"
|
||||
import { useContent } from "~utils/editMarkdownHook"
|
||||
import Turndown from "~utils/turndown"
|
||||
|
||||
export const config: PlasmoCSConfig = {
|
||||
@@ -26,29 +15,16 @@ export const config: PlasmoCSConfig = {
|
||||
}
|
||||
|
||||
const turndownService = Turndown()
|
||||
const articleTitle = document
|
||||
.querySelector<HTMLElement>("head title")
|
||||
.innerText.trim()
|
||||
const articleTitle = document.querySelector<HTMLElement>("head title").innerText
|
||||
|
||||
const HOST_ID = "codebox-jianshu"
|
||||
export const getShadowHostId: PlasmoGetShadowHostId = () => HOST_ID
|
||||
|
||||
export const getOverlayAnchor: PlasmoGetOverlayAnchor = async () =>
|
||||
document.querySelector("section.ouvJEz")
|
||||
|
||||
export const getStyle: PlasmoGetStyle = () => TagBtnStyle()
|
||||
|
||||
const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
const [parseContent, setParseContent] = useParseMarkdown()
|
||||
const [allShowTag, setAllShowTag] = useStorage("config-allShowTag", true)
|
||||
const [showTag, setShowTag] = useStorage<boolean>("jianshu-showTag", true)
|
||||
export default function Jianshu() {
|
||||
const [cssCode, runCss] = useCssCodeHook("jianshu")
|
||||
const [closeLoginModal] = useStorage<boolean>("jianshu-closeLoginModal")
|
||||
const [copyCode] = useStorage<boolean>("jianshu-copyCode")
|
||||
const [autoOpenCode] = useStorage<boolean>("jianshu-autoOpenCode")
|
||||
const [history, setHistory] = useStorage<any[]>("codebox-history")
|
||||
const [closeLog] = useStorage("config-closeLog", true)
|
||||
const [content, setContent] = useEditMarkdown()
|
||||
const [content, setContent] = useContent()
|
||||
|
||||
useEffect(() => {
|
||||
closeLog ||
|
||||
@@ -63,7 +39,7 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
res.send({ isShow: true })
|
||||
}
|
||||
if (req.name == "jianshu-editMarkdown") {
|
||||
editMarkdown()
|
||||
setContent("section.ouvJEz")
|
||||
}
|
||||
if (req.name == "jianshu-downloadMarkdown") {
|
||||
downloadMarkdown()
|
||||
@@ -71,9 +47,6 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
if (req.name == "jianshu-downloadHtml") {
|
||||
downloadHtml()
|
||||
}
|
||||
if (req.name == "jianshu-downloadPdf") {
|
||||
downloadPdf()
|
||||
}
|
||||
})
|
||||
|
||||
// 一键复制
|
||||
@@ -176,27 +149,6 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
}
|
||||
}
|
||||
|
||||
function getDescription() {
|
||||
const summary = document.querySelector<HTMLMetaElement>(
|
||||
'meta[name="description"]'
|
||||
).content
|
||||
summary && prompt("文章摘要:", summary)
|
||||
}
|
||||
|
||||
function downloadPdf() {
|
||||
const article = document.querySelector<HTMLElement>("section.ouvJEz")
|
||||
if (article) {
|
||||
Print.print(article, { title: articleTitle })
|
||||
.then(() => console.log("Printing complete"))
|
||||
.catch((error) => console.error("Printing failed:", error))
|
||||
}
|
||||
}
|
||||
|
||||
function editMarkdown() {
|
||||
const dom = document.querySelector("section.ouvJEz")
|
||||
setContent(dom, articleTitle)
|
||||
}
|
||||
|
||||
function downloadMarkdown() {
|
||||
const html = document.querySelector("section.ouvJEz")
|
||||
const markdown = turndownService.turndown(html)
|
||||
@@ -208,22 +160,5 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
saveHtml(dom, articleTitle)
|
||||
}
|
||||
|
||||
function parseMarkdown() {
|
||||
const dom = document.querySelector("section.ouvJEz")
|
||||
setParseContent(dom)
|
||||
}
|
||||
|
||||
return showTag && allShowTag ? (
|
||||
<ToolBox
|
||||
onGetDescription={getDescription}
|
||||
onEditMarkdown={editMarkdown}
|
||||
onDownloadMarkdown={downloadMarkdown}
|
||||
onPrint={downloadPdf}
|
||||
onParseMarkdown={parseMarkdown}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
return <div style={{ display: "none" }}></div>
|
||||
}
|
||||
|
||||
export default PlasmoOverlay
|
||||
|
||||
@@ -5,21 +5,18 @@ import type {
|
||||
PlasmoGetShadowHostId,
|
||||
PlasmoGetStyle
|
||||
} from "plasmo"
|
||||
import React, { useEffect, useRef, useState, type FC } from "react"
|
||||
import { useEffect, useRef, type FC } from "react"
|
||||
|
||||
import { useMessage } from "@plasmohq/messaging/hook"
|
||||
import { useStorage } from "@plasmohq/storage/dist/hook"
|
||||
|
||||
import ToolBox from "~component/ui/toolBox"
|
||||
import { i18n, saveHtml, saveMarkdown } from "~tools"
|
||||
import useCssCodeHook from "~utils/cssCodeHook"
|
||||
import { useEditMarkdown } from "~utils/editMarkdownHook"
|
||||
import { useParseMarkdown } from "~utils/parseMarkdownHook"
|
||||
import { Print } from "~utils/print"
|
||||
import { useContent } from "~utils/editMarkdownHook"
|
||||
import Turndown from "~utils/turndown"
|
||||
|
||||
export const config: PlasmoCSConfig = {
|
||||
matches: ["https://*.juejin.cn/post/*"]
|
||||
matches: ["https://*.juejin.cn/*"]
|
||||
}
|
||||
|
||||
const turndownService = Turndown({
|
||||
@@ -52,29 +49,46 @@ const turndownService = Turndown({
|
||||
}
|
||||
}
|
||||
})
|
||||
const articleTitle = document
|
||||
.querySelector<HTMLElement>("head title")!
|
||||
.innerText.trim()
|
||||
const articleTitle = document.querySelector<HTMLElement>("head title").innerText
|
||||
|
||||
const HOST_ID = "codebox-juejin"
|
||||
export const getShadowHostId: PlasmoGetShadowHostId = () => HOST_ID
|
||||
|
||||
export const getOverlayAnchor: PlasmoGetOverlayAnchor = async () =>
|
||||
document.querySelector("#juejin")
|
||||
document.querySelector("article.article .article-title")
|
||||
|
||||
export const getStyle: PlasmoGetStyle = () => {
|
||||
const style = document.createElement("style")
|
||||
style.textContent = `
|
||||
.codebox-tagBtn {
|
||||
height: 28px;
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
color: #1e80ff;
|
||||
width: 60px;
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
justify-content: space-between;
|
||||
padding: 0 8px;
|
||||
margin-top: -30px;
|
||||
font-size: 14px;
|
||||
}
|
||||
`
|
||||
return style
|
||||
}
|
||||
|
||||
const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
const [parseContent, setParseContent] = useParseMarkdown()
|
||||
const [allShowTag, setAllShowTag] = useStorage("config-allShowTag", true)
|
||||
const [showTag, setShowTag] = useStorage<boolean>("juejin-showTag", true)
|
||||
const [showTag, setShowTag] = useStorage<boolean>("juejin-showTag")
|
||||
const [cssCode, runCss] = useCssCodeHook("juejin")
|
||||
const [content, setContent] = useEditMarkdown()
|
||||
const [content, setContent] = useContent()
|
||||
|
||||
useMessage(async (req, res) => {
|
||||
if (req.name == "juejin-isShow") {
|
||||
res.send({ isShow: true })
|
||||
}
|
||||
if (req.name == "juejin-editMarkdown") {
|
||||
editMarkdown()
|
||||
setContent("article.article")
|
||||
}
|
||||
if (req.name == "juejin-downloadMarkdown") {
|
||||
downloadMarkdown()
|
||||
@@ -82,32 +96,8 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
if (req.name == "juejin-downloadHtml") {
|
||||
downloadHtml()
|
||||
}
|
||||
if (req.name == "juejin-downloadPdf") {
|
||||
downloadPdf()
|
||||
}
|
||||
})
|
||||
|
||||
function getDescription() {
|
||||
const summary = document.querySelector<HTMLMetaElement>(
|
||||
'meta[name="description"]'
|
||||
).content
|
||||
summary && prompt("文章摘要:", summary)
|
||||
}
|
||||
|
||||
function downloadPdf() {
|
||||
const article = document.querySelector<HTMLElement>("article.article")
|
||||
if (article) {
|
||||
Print.print(article, { title: articleTitle })
|
||||
.then(() => console.log("Printing complete"))
|
||||
.catch((error) => console.error("Printing failed:", error))
|
||||
}
|
||||
}
|
||||
|
||||
function editMarkdown() {
|
||||
const dom = document.querySelector("article.article")
|
||||
setContent(dom, articleTitle)
|
||||
}
|
||||
|
||||
function downloadMarkdown() {
|
||||
const html = document.querySelector("article.article")
|
||||
const markdown = turndownService.turndown(html)
|
||||
@@ -119,19 +109,25 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
saveHtml(dom, articleTitle)
|
||||
}
|
||||
|
||||
function parseMarkdown() {
|
||||
const dom = document.querySelector("article.article")
|
||||
setParseContent(dom)
|
||||
function handleEdit() {
|
||||
setContent("article.article")
|
||||
}
|
||||
|
||||
return showTag && allShowTag ? (
|
||||
<ToolBox
|
||||
onGetDescription={getDescription}
|
||||
onEditMarkdown={editMarkdown}
|
||||
onDownloadMarkdown={downloadMarkdown}
|
||||
onPrint={downloadPdf}
|
||||
onParseMarkdown={parseMarkdown}
|
||||
/>
|
||||
function handleDownload() {
|
||||
const html = document.querySelector("article.article")
|
||||
const markdown = turndownService.turndown(html)
|
||||
saveMarkdown(markdown, articleTitle)
|
||||
}
|
||||
|
||||
function closeTag() {
|
||||
setShowTag(false)
|
||||
}
|
||||
|
||||
return showTag ? (
|
||||
<div className="codebox-tagBtn">
|
||||
<div onClick={handleEdit}>{i18n("edit")}</div>
|
||||
<div onClick={handleDownload}>{i18n("download")}</div>
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
import dayjs from "dayjs"
|
||||
import type { PlasmoCSConfig } from "plasmo"
|
||||
import React, { useEffect, useState } from "react"
|
||||
|
||||
import { Storage } from "@plasmohq/storage"
|
||||
import { useStorage } from "@plasmohq/storage/hook"
|
||||
|
||||
import QRCodeModal from "~component/ui/QRCodeModal"
|
||||
|
||||
export const config: PlasmoCSConfig = {
|
||||
matches: ["https://kimi.moonshot.cn/*", "https://kimi.moonshot.cn/chat/*"]
|
||||
}
|
||||
|
||||
export default function Kimi() {
|
||||
const [validTime, setValidTime] = useStorage("ai-validTime", "1737872293")
|
||||
const [isModalOpen, setIsModalOpen] = useState(false)
|
||||
const [content, setContent] = useStorage({
|
||||
key: "ai-content",
|
||||
instance: new Storage({
|
||||
area: "local"
|
||||
})
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
let timer = null
|
||||
let index = 0
|
||||
if (content) {
|
||||
if (Number(validTime) < dayjs().unix()) {
|
||||
timer = setInterval(() => {
|
||||
const editorElement = document.querySelector(
|
||||
"div[data-lexical-editor=true]"
|
||||
)
|
||||
index++
|
||||
if (editorElement && index < 30) {
|
||||
setIsModalOpen(true)
|
||||
clearTimeout(timer)
|
||||
} else if (index >= 30) {
|
||||
clearTimeout(timer)
|
||||
}
|
||||
}, 1000)
|
||||
} else {
|
||||
handleSetContent()
|
||||
}
|
||||
}
|
||||
return () => {
|
||||
clearTimeout(timer)
|
||||
}
|
||||
}, [content, validTime])
|
||||
|
||||
const handleCancelModal = () => {
|
||||
setContent("")
|
||||
setIsModalOpen(false)
|
||||
}
|
||||
|
||||
function handleConfirmModal() {
|
||||
let time = dayjs().add(1, "day").unix()
|
||||
|
||||
setValidTime(String(time))
|
||||
handleSetContent()
|
||||
setTimeout(() => {
|
||||
setIsModalOpen(false)
|
||||
}, 500)
|
||||
}
|
||||
|
||||
function handleSetContent() {
|
||||
const editorElement = document.querySelector(
|
||||
"div[data-lexical-editor=true]"
|
||||
) as HTMLElement
|
||||
|
||||
const buttonElement = document.querySelector(
|
||||
".chat-editor-action .send-button"
|
||||
) as HTMLElement
|
||||
|
||||
if (editorElement) {
|
||||
editorElement.focus()
|
||||
|
||||
const event = new InputEvent("input", {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
data: content,
|
||||
inputType: "insertText"
|
||||
})
|
||||
|
||||
editorElement.dispatchEvent(event)
|
||||
setContent("")
|
||||
|
||||
setTimeout(() => {
|
||||
buttonElement.click()
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{isModalOpen && content && (
|
||||
<QRCodeModal
|
||||
onClose={handleCancelModal}
|
||||
onConfirm={handleConfirmModal}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
import type {
|
||||
PlasmoCSConfig,
|
||||
PlasmoCSUIProps,
|
||||
PlasmoGetShadowHostId
|
||||
} from "plasmo"
|
||||
import React, { type FC } from "react"
|
||||
|
||||
import { useMessage } from "@plasmohq/messaging/hook"
|
||||
import { useStorage } from "@plasmohq/storage/dist/hook"
|
||||
|
||||
import ToolBox from "~component/ui/toolBox"
|
||||
import { saveHtml, saveMarkdown } from "~tools"
|
||||
import useCssCodeHook from "~utils/cssCodeHook"
|
||||
import { useEditMarkdown } from "~utils/editMarkdownHook"
|
||||
import { useParseMarkdown } from "~utils/parseMarkdownHook"
|
||||
import { Print } from "~utils/print"
|
||||
import Turndown from "~utils/turndown"
|
||||
|
||||
export const config: PlasmoCSConfig = {
|
||||
matches: ["https://*.luogu.com.cn/article/*"]
|
||||
}
|
||||
|
||||
const turndownService = Turndown()
|
||||
const articleTitle = document
|
||||
.querySelector<HTMLElement>("head title")
|
||||
.innerText.trim()
|
||||
|
||||
export const getShadowHostId: PlasmoGetShadowHostId = () => "codebox-luogu"
|
||||
|
||||
const PlasmoOverlay: FC<PlasmoCSUIProps> = () => {
|
||||
const [parseContent, setParseContent] = useParseMarkdown()
|
||||
const [allShowTag, setAllShowTag] = useStorage("config-allShowTag", true)
|
||||
const [showTag, setShowTag] = useStorage<boolean>("luogu-showTag", true)
|
||||
const [cssCode, runCss] = useCssCodeHook("luogu")
|
||||
const [content, setContent] = useEditMarkdown()
|
||||
|
||||
useMessage(async (req, res) => {
|
||||
if (req.name == "luogu-isShow") {
|
||||
res.send({ isShow: true })
|
||||
}
|
||||
if (req.name == "luogu-editMarkdown") {
|
||||
editMarkdown()
|
||||
}
|
||||
if (req.name == "luogu-downloadMarkdown") {
|
||||
downloadMarkdown()
|
||||
}
|
||||
if (req.name == "luogu-downloadHtml") {
|
||||
downloadHtml()
|
||||
}
|
||||
if (req.name == "luogu-downloadPdf") {
|
||||
downloadPdf()
|
||||
}
|
||||
})
|
||||
|
||||
function getDescription() {
|
||||
const summary = document.querySelector<HTMLMetaElement>(
|
||||
'meta[name="description"]'
|
||||
).content
|
||||
summary && prompt("文章摘要:", summary)
|
||||
}
|
||||
|
||||
function downloadPdf() {
|
||||
const article = document.querySelector<HTMLElement>(".article-content")
|
||||
if (article) {
|
||||
Print.print(article, { title: articleTitle })
|
||||
.then(() => console.log("Printing complete"))
|
||||
.catch((error) => console.error("Printing failed:", error))
|
||||
}
|
||||
}
|
||||
|
||||
function editMarkdown() {
|
||||
const dom = document.querySelector(".article-content")
|
||||
setContent(dom, articleTitle)
|
||||
}
|
||||
|
||||
function downloadMarkdown() {
|
||||
const html = document.querySelector(".article-content")
|
||||
const markdown = turndownService.turndown(html)
|
||||
saveMarkdown(markdown, articleTitle)
|
||||
}
|
||||
|
||||
function downloadHtml() {
|
||||
const dom = document.querySelector(".article-content")
|
||||
saveHtml(dom, articleTitle)
|
||||
}
|
||||
|
||||
function parseMarkdown() {
|
||||
const dom = document.querySelector(".article-content")
|
||||
setParseContent(dom)
|
||||
}
|
||||
|
||||
return showTag && allShowTag ? (
|
||||
<ToolBox
|
||||
style={{
|
||||
left: "75px"
|
||||
}}
|
||||
onGetDescription={getDescription}
|
||||
onEditMarkdown={editMarkdown}
|
||||
onDownloadMarkdown={downloadMarkdown}
|
||||
onPrint={downloadPdf}
|
||||
onParseMarkdown={parseMarkdown}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
}
|
||||
|
||||
export default PlasmoOverlay
|
||||
@@ -5,33 +5,25 @@ import { Storage } from "@plasmohq/storage"
|
||||
import { useStorage } from "@plasmohq/storage/dist/hook"
|
||||
|
||||
export const config: PlasmoCSConfig = {
|
||||
matches: ["https://md.randbox.top/*", "https://md.code-box.fun/*"]
|
||||
matches: ["https://md.randbox.top/*"]
|
||||
}
|
||||
|
||||
export default function Markdown() {
|
||||
const [post, setPost] = useStorage({
|
||||
key: "md-post",
|
||||
const [content] = useStorage({
|
||||
key: "md-content",
|
||||
instance: new Storage({
|
||||
area: "local"
|
||||
})
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (post) {
|
||||
const posts = JSON.parse(window.localStorage.getItem("MD__posts")) || []
|
||||
const _post = JSON.parse(post)
|
||||
|
||||
if (posts[0] && _post.content != posts[0].content) {
|
||||
posts.unshift({
|
||||
content: _post.content,
|
||||
title: _post.title || "文章1"
|
||||
})
|
||||
window.localStorage.setItem("MD__posts", JSON.stringify(posts))
|
||||
setPost("")
|
||||
if (content) {
|
||||
if (window.localStorage.getItem("__editor_content") != content) {
|
||||
window.localStorage.setItem("__editor_content", content)
|
||||
location.reload()
|
||||
}
|
||||
}
|
||||
}, [post])
|
||||
}, [content])
|
||||
|
||||
return <div style={{ display: "none" }}></div>
|
||||
}
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
import type {
|
||||
PlasmoCSConfig,
|
||||
PlasmoCSUIProps,
|
||||
PlasmoGetShadowHostId
|
||||
PlasmoGetOverlayAnchor,
|
||||
PlasmoGetShadowHostId,
|
||||
PlasmoGetStyle
|
||||
} from "plasmo"
|
||||
import { useEffect, useRef, type FC } from "react"
|
||||
|
||||
import { useMessage } from "@plasmohq/messaging/hook"
|
||||
import { useStorage } from "@plasmohq/storage/dist/hook"
|
||||
|
||||
import ToolBox from "~component/ui/toolBox"
|
||||
import { i18n, saveHtml, saveMarkdown } from "~tools"
|
||||
import useCssCodeHook from "~utils/cssCodeHook"
|
||||
import { useEditMarkdown } from "~utils/editMarkdownHook"
|
||||
import { useParseMarkdown } from "~utils/parseMarkdownHook"
|
||||
import { Print } from "~utils/print"
|
||||
import { useContent } from "~utils/editMarkdownHook"
|
||||
import Turndown from "~utils/turndown"
|
||||
|
||||
export const config: PlasmoCSConfig = {
|
||||
@@ -91,60 +90,55 @@ const turndownOption = {
|
||||
}
|
||||
|
||||
const turndownService = Turndown(turndownOption)
|
||||
const articleTitle = document
|
||||
.querySelector<HTMLElement>("head title")
|
||||
.innerText.trim()
|
||||
const articleTitle = document.querySelector<HTMLElement>("head title").innerText
|
||||
|
||||
export const getShadowHostId: PlasmoGetShadowHostId = () => "codebox-medium"
|
||||
const HOST_ID = "codebox-medium"
|
||||
export const getShadowHostId: PlasmoGetShadowHostId = () => HOST_ID
|
||||
|
||||
const PlasmoOverlay: FC<PlasmoCSUIProps> = () => {
|
||||
const [parseContent, setParseContent] = useParseMarkdown()
|
||||
const [allShowTag, setAllShowTag] = useStorage("config-allShowTag", true)
|
||||
const [showTag, setShowTag] = useStorage<boolean>("medium-showTag", true)
|
||||
export const getOverlayAnchor: PlasmoGetOverlayAnchor = async () =>
|
||||
document.querySelector("article .pw-post-title")
|
||||
|
||||
export const getStyle: PlasmoGetStyle = () => {
|
||||
const style = document.createElement("style")
|
||||
style.textContent = `
|
||||
.codebox-tagBtn {
|
||||
height: 28px;
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
color: #1e80ff;
|
||||
width: 60px;
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
justify-content: space-between;
|
||||
padding: 0 8px;
|
||||
margin-top: -30px;
|
||||
font-size: 14px;
|
||||
}
|
||||
`
|
||||
return style
|
||||
}
|
||||
|
||||
const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
const [showTag, setShowTag] = useStorage<boolean>("medium-showTag")
|
||||
const [cssCode, runCss] = useCssCodeHook("medium")
|
||||
const [content, setContent] = useEditMarkdown(turndownOption)
|
||||
const [content, setContent] = useContent(turndownOption)
|
||||
|
||||
useMessage(async (req, res) => {
|
||||
switch (req.name) {
|
||||
case "medium-isShow":
|
||||
res.send({ isShow: true })
|
||||
break
|
||||
case "medium-editMarkdown":
|
||||
editMarkdown()
|
||||
break
|
||||
case "medium-downloadMarkdown":
|
||||
downloadMarkdown()
|
||||
break
|
||||
case "medium-downloadHtml":
|
||||
downloadHtml()
|
||||
break
|
||||
case "medium-downloadPdf":
|
||||
downloadPdf()
|
||||
break
|
||||
if (req.name == "medium-isShow") {
|
||||
res.send({ isShow: true })
|
||||
}
|
||||
if (req.name == "medium-editMarkdown") {
|
||||
setContent("article.article")
|
||||
}
|
||||
if (req.name == "medium-downloadMarkdown") {
|
||||
downloadMarkdown()
|
||||
}
|
||||
if (req.name == "medium-downloadHtml") {
|
||||
downloadHtml()
|
||||
}
|
||||
})
|
||||
|
||||
function getDescription() {
|
||||
const summary = document.querySelector<HTMLMetaElement>(
|
||||
'meta[name="description"]'
|
||||
).content
|
||||
summary && prompt("文章摘要:", summary)
|
||||
}
|
||||
|
||||
function downloadPdf() {
|
||||
const article = document.querySelector<HTMLElement>("article")
|
||||
if (article) {
|
||||
Print.print(article, { title: articleTitle })
|
||||
.then(() => console.log("Printing complete"))
|
||||
.catch((error) => console.error("Printing failed:", error))
|
||||
}
|
||||
}
|
||||
|
||||
function editMarkdown() {
|
||||
const dom = document.querySelector("article")
|
||||
setContent(dom, articleTitle)
|
||||
}
|
||||
|
||||
function downloadMarkdown() {
|
||||
const html = document.querySelector("article")
|
||||
const markdown = turndownService.turndown(html)
|
||||
@@ -156,19 +150,25 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = () => {
|
||||
saveHtml(dom, articleTitle)
|
||||
}
|
||||
|
||||
function parseMarkdown() {
|
||||
const dom = document.querySelector("article")
|
||||
setParseContent(dom)
|
||||
function handleEdit() {
|
||||
setContent("article")
|
||||
}
|
||||
|
||||
return showTag && allShowTag ? (
|
||||
<ToolBox
|
||||
onGetDescription={getDescription}
|
||||
onEditMarkdown={editMarkdown}
|
||||
onDownloadMarkdown={downloadMarkdown}
|
||||
onPrint={downloadPdf}
|
||||
onParseMarkdown={parseMarkdown}
|
||||
/>
|
||||
function handleDownload() {
|
||||
const html = document.querySelector("article")
|
||||
const markdown = turndownService.turndown(html)
|
||||
saveMarkdown(markdown, articleTitle)
|
||||
}
|
||||
|
||||
function closeTag() {
|
||||
setShowTag(false)
|
||||
}
|
||||
|
||||
return showTag ? (
|
||||
<div className="codebox-tagBtn">
|
||||
<div onClick={handleEdit}>{i18n("edit")}</div>
|
||||
<div onClick={handleDownload}>{i18n("download")}</div>
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
import type {
|
||||
PlasmoCSConfig,
|
||||
PlasmoCSUIProps,
|
||||
PlasmoGetOverlayAnchorList,
|
||||
PlasmoGetShadowHostId
|
||||
} from "plasmo"
|
||||
import { type FC } from "react"
|
||||
|
||||
import { i18n } from "~tools"
|
||||
|
||||
export const config: PlasmoCSConfig = {
|
||||
matches: ["https://mp.weixin.qq.com/cgi-bin/*"]
|
||||
}
|
||||
|
||||
const HOST_ID = "codebox-weixin"
|
||||
export const getShadowHostId: PlasmoGetShadowHostId = () => HOST_ID
|
||||
|
||||
export const getOverlayAnchorList: PlasmoGetOverlayAnchorList = async () =>
|
||||
document.querySelectorAll(
|
||||
".weui-desktop-img-picker__item .weui-desktop-img-picker__img-title"
|
||||
)
|
||||
|
||||
const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
function handleCopy() {
|
||||
try {
|
||||
const item = anchor.element.closest(".weui-desktop-img-picker__item")
|
||||
const img = item.querySelector(".weui-desktop-img-picker__img-thumb")
|
||||
const computedStyle = window.getComputedStyle(img)
|
||||
const backgroundImage = computedStyle.getPropertyValue("background-image")
|
||||
const imageUrlMatch = backgroundImage.match(/url\(["']?(.*?)["']?\)/)
|
||||
|
||||
if (imageUrlMatch && imageUrlMatch[1]) {
|
||||
const imageUrl = imageUrlMatch[1]
|
||||
|
||||
navigator.clipboard.writeText(imageUrl)
|
||||
alert("URL 已复制到剪贴板")
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("复制失败:", error)
|
||||
alert("复制失败")
|
||||
}
|
||||
}
|
||||
|
||||
return <button onClick={handleCopy}>{i18n("copyURL")}</button>
|
||||
}
|
||||
|
||||
export default PlasmoOverlay
|
||||
@@ -1,22 +1,10 @@
|
||||
import type {
|
||||
PlasmoCSConfig,
|
||||
PlasmoCSUIProps,
|
||||
PlasmoGetOverlayAnchor,
|
||||
PlasmoGetShadowHostId,
|
||||
PlasmoGetStyle
|
||||
} from "plasmo"
|
||||
import React, { type FC } from "react"
|
||||
import type { PlasmoCSConfig } from "plasmo"
|
||||
|
||||
import { useMessage } from "@plasmohq/messaging/hook"
|
||||
import { useStorage } from "@plasmohq/storage/dist/hook"
|
||||
|
||||
import TagBtnStyle from "~component/tagBtn/style"
|
||||
import ToolBox from "~component/ui/toolBox"
|
||||
import { saveHtml, saveMarkdown } from "~tools"
|
||||
import useCssCodeHook from "~utils/cssCodeHook"
|
||||
import { useEditMarkdown } from "~utils/editMarkdownHook"
|
||||
import { useParseMarkdown } from "~utils/parseMarkdownHook"
|
||||
import { Print } from "~utils/print"
|
||||
import { useContent } from "~utils/editMarkdownHook"
|
||||
import Turndown from "~utils/turndown"
|
||||
|
||||
export const config: PlasmoCSConfig = {
|
||||
@@ -24,32 +12,18 @@ export const config: PlasmoCSConfig = {
|
||||
}
|
||||
|
||||
const turndownService = Turndown()
|
||||
const articleTitle = document
|
||||
.querySelector<HTMLElement>("head title")
|
||||
.innerText.trim()
|
||||
const articleTitle = document.querySelector<HTMLElement>("head title").innerText
|
||||
|
||||
const HOST_ID = "codebox-oschina"
|
||||
export const getShadowHostId: PlasmoGetShadowHostId = () => HOST_ID
|
||||
|
||||
export const getOverlayAnchor: PlasmoGetOverlayAnchor = async () =>
|
||||
document.querySelector(".blog-detail-container") ||
|
||||
document.querySelector(".news-detail-container")
|
||||
|
||||
export const getStyle: PlasmoGetStyle = () => TagBtnStyle()
|
||||
|
||||
const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
const [parseContent, setParseContent] = useParseMarkdown()
|
||||
const [allShowTag, setAllShowTag] = useStorage("config-allShowTag", true)
|
||||
const [showTag, setShowTag] = useStorage<boolean>("oschina-showTag", true)
|
||||
export default function Oschina() {
|
||||
const [cssCode, runCss] = useCssCodeHook("oschina")
|
||||
const [content, setContent] = useEditMarkdown()
|
||||
const [content, setContent] = useContent()
|
||||
|
||||
useMessage(async (req, res) => {
|
||||
if (req.name == "oschina-isShow") {
|
||||
res.send({ isShow: true })
|
||||
}
|
||||
if (req.name == "oschina-editMarkdown") {
|
||||
editMarkdown()
|
||||
setContent(".article-box")
|
||||
}
|
||||
if (req.name == "oschina-downloadMarkdown") {
|
||||
downloadMarkdown()
|
||||
@@ -57,32 +31,8 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
if (req.name == "oschina-downloadHtml") {
|
||||
downloadHtml()
|
||||
}
|
||||
if (req.name == "oschina-downloadPdf") {
|
||||
downloadPdf()
|
||||
}
|
||||
})
|
||||
|
||||
function getDescription() {
|
||||
const summary = document.querySelector<HTMLMetaElement>(
|
||||
'meta[name="description"]'
|
||||
).content
|
||||
summary && prompt("文章摘要:", summary)
|
||||
}
|
||||
|
||||
function downloadPdf() {
|
||||
const article = document.querySelector<HTMLElement>(".article-box")
|
||||
if (article) {
|
||||
Print.print(article, { title: articleTitle })
|
||||
.then(() => console.log("Printing complete"))
|
||||
.catch((error) => console.error("Printing failed:", error))
|
||||
}
|
||||
}
|
||||
|
||||
function editMarkdown() {
|
||||
const dom = document.querySelector(".article-box")
|
||||
setContent(dom, articleTitle)
|
||||
}
|
||||
|
||||
function downloadMarkdown() {
|
||||
const html = document.querySelector(".article-box")
|
||||
const markdown = turndownService.turndown(html)
|
||||
@@ -94,22 +44,5 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
saveHtml(dom, articleTitle)
|
||||
}
|
||||
|
||||
function parseMarkdown() {
|
||||
const dom = document.querySelector(".article-box")
|
||||
setParseContent(dom)
|
||||
}
|
||||
|
||||
return showTag && allShowTag ? (
|
||||
<ToolBox
|
||||
onGetDescription={getDescription}
|
||||
onEditMarkdown={editMarkdown}
|
||||
onDownloadMarkdown={downloadMarkdown}
|
||||
onPrint={downloadPdf}
|
||||
onParseMarkdown={parseMarkdown}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
return <div style={{ display: "none" }}></div>
|
||||
}
|
||||
|
||||
export default PlasmoOverlay
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
import type {
|
||||
PlasmoCSConfig,
|
||||
PlasmoCSUIProps,
|
||||
PlasmoGetOverlayAnchorList,
|
||||
PlasmoGetShadowHostId
|
||||
} from "plasmo"
|
||||
import React, { type FC } from "react"
|
||||
|
||||
import { useMessage } from "@plasmohq/messaging/dist/hook"
|
||||
import { useStorage } from "@plasmohq/storage/dist/hook"
|
||||
|
||||
import ToolBox from "~component/ui/toolBox"
|
||||
import { i18n, saveHtml, saveMarkdown } from "~tools"
|
||||
import useCssCodeHook from "~utils/cssCodeHook"
|
||||
import { useEditMarkdown } from "~utils/editMarkdownHook"
|
||||
import { useParseMarkdown } from "~utils/parseMarkdownHook"
|
||||
import { Print } from "~utils/print"
|
||||
import Turndown from "~utils/turndown"
|
||||
|
||||
export const config: PlasmoCSConfig = {
|
||||
matches: [
|
||||
"https://paywallbuster.com/articles/*",
|
||||
"https://archive.is/*",
|
||||
"https://archive.ph/*"
|
||||
]
|
||||
}
|
||||
|
||||
const turndownService = Turndown()
|
||||
const articleTitle = document
|
||||
.querySelector<HTMLElement>("head title")
|
||||
.innerText.trim()
|
||||
|
||||
export const getShadowHostId: PlasmoGetShadowHostId = () =>
|
||||
"codebox-paywallbuster"
|
||||
const boxStyles = {
|
||||
box: {
|
||||
position: "fixed" as const,
|
||||
border: "1px solid #D9DADC",
|
||||
left: "25px",
|
||||
top: "30px",
|
||||
textAlign: "center" as const,
|
||||
width: "140px",
|
||||
padding: "5px",
|
||||
cursor: "pointer"
|
||||
}
|
||||
}
|
||||
const isPaywallbuster = location.hostname.includes("paywallbuster")
|
||||
|
||||
const PlasmoOverlay: FC<PlasmoCSUIProps> = () => {
|
||||
const [parseContent, setParseContent] = useParseMarkdown()
|
||||
const [allShowTag, setAllShowTag] = useStorage("config-allShowTag", true)
|
||||
const [showTag, setShowTag] = useStorage<boolean>(
|
||||
"paywallbuster-showTag",
|
||||
true
|
||||
)
|
||||
const [cssCode, runCss] = useCssCodeHook("paywallbuster")
|
||||
const [content, setContent] = useEditMarkdown()
|
||||
|
||||
useMessage(async (req, res) => {
|
||||
if (req.name == "paywallbuster-isShow") {
|
||||
res.send({ isShow: true })
|
||||
}
|
||||
if (req.name == "paywallbuster-editMarkdown") {
|
||||
editMarkdown()
|
||||
}
|
||||
if (req.name == "paywallbuster-downloadMarkdown") {
|
||||
downloadMarkdown()
|
||||
}
|
||||
if (req.name == "paywallbuster-downloadHtml") {
|
||||
downloadHtml()
|
||||
}
|
||||
if (req.name == "paywallbuster-downloadPdf") {
|
||||
downloadPdf()
|
||||
}
|
||||
})
|
||||
|
||||
function getDescription() {
|
||||
const summary = document.querySelector<HTMLMetaElement>(
|
||||
'meta[name="description"]'
|
||||
).content
|
||||
summary && prompt("文章摘要:", summary)
|
||||
}
|
||||
|
||||
function downloadPdf() {
|
||||
const article = document.querySelector<HTMLElement>("article")
|
||||
if (article) {
|
||||
Print.print(article, { title: articleTitle })
|
||||
.then(() => console.log("Printing complete"))
|
||||
.catch((error) => console.error("Printing failed:", error))
|
||||
}
|
||||
}
|
||||
|
||||
function editMarkdown() {
|
||||
const dom = document.querySelector("article")
|
||||
setContent(dom, articleTitle)
|
||||
}
|
||||
|
||||
function downloadMarkdown() {
|
||||
const html = document.querySelector("article")
|
||||
const markdown = turndownService.turndown(html)
|
||||
saveMarkdown(markdown, articleTitle)
|
||||
}
|
||||
|
||||
function downloadHtml() {
|
||||
const dom = document.querySelector("article")
|
||||
saveHtml(dom, articleTitle)
|
||||
}
|
||||
|
||||
function parseMarkdown() {
|
||||
const dom = document.querySelector("article")
|
||||
setParseContent(dom)
|
||||
}
|
||||
|
||||
function handleOpenSource() {
|
||||
const iframe = document.querySelector<any>("#content-frame")
|
||||
iframe && window.open(iframe.src, "_blank")
|
||||
}
|
||||
|
||||
return showTag ? (
|
||||
isPaywallbuster ? (
|
||||
<div style={boxStyles.box}>
|
||||
<a onClick={handleOpenSource}>打开源链接</a>
|
||||
</div>
|
||||
) : (
|
||||
<ToolBox
|
||||
onGetDescription={getDescription}
|
||||
onEditMarkdown={editMarkdown}
|
||||
onDownloadMarkdown={downloadMarkdown}
|
||||
onPrint={downloadPdf}
|
||||
onParseMarkdown={parseMarkdown}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
}
|
||||
|
||||
export default PlasmoOverlay
|
||||
@@ -1,23 +1,18 @@
|
||||
import { Button } from "antd"
|
||||
import type {
|
||||
PlasmoCSConfig,
|
||||
PlasmoCSUIProps,
|
||||
PlasmoGetOverlayAnchor,
|
||||
PlasmoGetShadowHostId,
|
||||
PlasmoGetStyle
|
||||
PlasmoGetInlineAnchorList
|
||||
} from "plasmo"
|
||||
import React, { useEffect, useState, type FC } from "react"
|
||||
import { useEffect, useState, type FC } from "react"
|
||||
import { v4 as uuidv4 } from "uuid"
|
||||
|
||||
import { useMessage } from "@plasmohq/messaging/hook"
|
||||
import { useStorage } from "@plasmohq/storage/hook"
|
||||
|
||||
import TagBtnStyle from "~component/tagBtn/style"
|
||||
import Tags from "~component/ui/tags"
|
||||
import ToolBox from "~component/ui/toolBox"
|
||||
import { addCss, i18n, removeCss, saveHtml, saveMarkdown } from "~tools"
|
||||
import { addCss, removeCss, saveHtml, saveMarkdown } from "~tools"
|
||||
import useCssCodeHook from "~utils/cssCodeHook"
|
||||
import { useEditMarkdown } from "~utils/editMarkdownHook"
|
||||
import { useParseMarkdown } from "~utils/parseMarkdownHook"
|
||||
import { Print } from "~utils/print"
|
||||
import { useContent } from "~utils/editMarkdownHook"
|
||||
import Turndown from "~utils/turndown"
|
||||
|
||||
export const config: PlasmoCSConfig = {
|
||||
@@ -25,28 +20,61 @@ export const config: PlasmoCSConfig = {
|
||||
}
|
||||
|
||||
const turndownService = Turndown()
|
||||
const articleTitle = document
|
||||
.querySelector<HTMLElement>("head title")
|
||||
.innerText.trim()
|
||||
const articleTitle = document.querySelector<HTMLElement>("head title").innerText
|
||||
|
||||
const HOST_ID = "codebox-php"
|
||||
export const getShadowHostId: PlasmoGetShadowHostId = () => HOST_ID
|
||||
export const getInlineAnchorList: PlasmoGetInlineAnchorList = async () => {
|
||||
const preList = document.querySelectorAll("pre")
|
||||
|
||||
export const getOverlayAnchor: PlasmoGetOverlayAnchor = async () =>
|
||||
document.querySelector(".wzContent .wzctTitle")
|
||||
const anchors = []
|
||||
Array.from(preList).map((pre) => {
|
||||
const classList = pre.classList
|
||||
if (pre.textContent && !classList.contains("CodeMirror-line"))
|
||||
anchors.push(pre)
|
||||
})
|
||||
|
||||
export const getStyle: PlasmoGetStyle = () => TagBtnStyle()
|
||||
return anchors.map((element) => ({
|
||||
element,
|
||||
insertPosition: "afterbegin"
|
||||
// insertPosition: "beforebegin"
|
||||
}))
|
||||
}
|
||||
|
||||
const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
const [parseContent, setParseContent] = useParseMarkdown()
|
||||
const [allShowTag, setAllShowTag] = useStorage("config-allShowTag", true)
|
||||
const [showTag, setShowTag] = useStorage<boolean>("php-showTag", true)
|
||||
const [cssCode, runCss] = useCssCodeHook("php")
|
||||
const [copyCode] = useStorage("php-copyCode", true)
|
||||
const [closeLoginModal] = useStorage<boolean>("php-closeLoginModal")
|
||||
const [history, setHistory] = useStorage<any[]>("codebox-history")
|
||||
const [closeLog] = useStorage("config-closeLog", true)
|
||||
const [content, setContent] = useEditMarkdown()
|
||||
const [content, setContent] = useContent()
|
||||
const [isCopy, setIsCopy] = useState(false)
|
||||
|
||||
const element = anchor.element
|
||||
const style = window.getComputedStyle(element)
|
||||
const marginTop = style.getPropertyValue("margin-top")
|
||||
|
||||
const onCopy = async () => {
|
||||
try {
|
||||
const target = anchor.element as HTMLElement
|
||||
const preBlock = target.closest("pre")
|
||||
const codeBlock = target.querySelector("code")
|
||||
let textContent = ""
|
||||
|
||||
if (codeBlock) {
|
||||
textContent = codeBlock.textContent
|
||||
} else {
|
||||
textContent = preBlock && preBlock.textContent
|
||||
}
|
||||
|
||||
navigator.clipboard.writeText(textContent)
|
||||
|
||||
setIsCopy(true)
|
||||
setTimeout(() => {
|
||||
setIsCopy(false)
|
||||
}, 1000)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
closeLog || console.log("PHP status", { closeLoginModal })
|
||||
@@ -59,7 +87,7 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
res.send({ isShow: true })
|
||||
}
|
||||
if (req.name == "php-editMarkdown") {
|
||||
editMarkdown()
|
||||
setContent(".phpscMain .php-article")
|
||||
}
|
||||
if (req.name == "php-downloadMarkdown") {
|
||||
downloadMarkdown()
|
||||
@@ -67,22 +95,8 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
if (req.name == "php-downloadHtml") {
|
||||
downloadHtml()
|
||||
}
|
||||
if (req.name == "oschina-downloadPdf") {
|
||||
downloadPdf()
|
||||
}
|
||||
})
|
||||
|
||||
function downloadPdf() {
|
||||
const article = document.querySelector<HTMLElement>(
|
||||
".phpscMain .php-article"
|
||||
)
|
||||
if (article) {
|
||||
Print.print(article, { title: articleTitle })
|
||||
.then(() => console.log("Printing complete"))
|
||||
.catch((error) => console.error("Printing failed:", error))
|
||||
}
|
||||
}
|
||||
|
||||
/* 未登录复制代码 */
|
||||
function copyCodeCssFunc(copyCode) {
|
||||
copyCode
|
||||
@@ -122,18 +136,6 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
addCss(css)
|
||||
}
|
||||
|
||||
function getDescription() {
|
||||
const summary = document.querySelector<HTMLMetaElement>(
|
||||
'meta[name="description"]'
|
||||
).content
|
||||
summary && prompt("文章摘要:", summary)
|
||||
}
|
||||
|
||||
function editMarkdown() {
|
||||
const dom = document.querySelector(".phpscMain .php-article")
|
||||
setContent(dom, articleTitle)
|
||||
}
|
||||
|
||||
function downloadMarkdown() {
|
||||
const html = document.querySelector(".phpscMain .php-article")
|
||||
const markdown = turndownService.turndown(html)
|
||||
@@ -145,21 +147,25 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
saveHtml(dom, articleTitle)
|
||||
}
|
||||
|
||||
function parseMarkdown() {
|
||||
const dom = document.querySelector(".phpscMain .php-article")
|
||||
setParseContent(dom)
|
||||
}
|
||||
|
||||
return showTag && allShowTag ? (
|
||||
<ToolBox
|
||||
onGetDescription={getDescription}
|
||||
onEditMarkdown={editMarkdown}
|
||||
onDownloadMarkdown={downloadMarkdown}
|
||||
onPrint={downloadPdf}
|
||||
onParseMarkdown={parseMarkdown}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
return (
|
||||
<>
|
||||
{copyCode ? (
|
||||
<div
|
||||
className="codebox-copyCodeHeader"
|
||||
style={{ marginBottom: "-" + marginTop }}>
|
||||
<span className="codebox-copyCodeLogo"></span>
|
||||
<Button
|
||||
color="primary"
|
||||
variant="filled"
|
||||
onClick={onCopy}
|
||||
className="codebox-copyCodeBtn">
|
||||
{isCopy ? "复制成功" : "复制"}
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
import type {
|
||||
PlasmoCSConfig,
|
||||
PlasmoCSUIProps,
|
||||
PlasmoGetShadowHostId
|
||||
} from "plasmo"
|
||||
import React, { type FC } from "react"
|
||||
|
||||
import { useMessage } from "@plasmohq/messaging/hook"
|
||||
import { useStorage } from "@plasmohq/storage/dist/hook"
|
||||
|
||||
import ToolBox from "~component/ui/toolBox"
|
||||
import { saveHtml, saveMarkdown } from "~tools"
|
||||
import useCssCodeHook from "~utils/cssCodeHook"
|
||||
import { useEditMarkdown } from "~utils/editMarkdownHook"
|
||||
import { useParseMarkdown } from "~utils/parseMarkdownHook"
|
||||
import { Print } from "~utils/print"
|
||||
import Turndown from "~utils/turndown"
|
||||
|
||||
export const config: PlasmoCSConfig = {
|
||||
matches: [
|
||||
"https://*.pianshen.com/question/*",
|
||||
"http://*.pianshen.com/article/*"
|
||||
]
|
||||
}
|
||||
|
||||
const turndownService = Turndown()
|
||||
const articleTitle = document
|
||||
.querySelector<HTMLElement>("head title")
|
||||
.innerText.trim()
|
||||
|
||||
export const getShadowHostId: PlasmoGetShadowHostId = () => "codebox-pianshen"
|
||||
|
||||
const PlasmoOverlay: FC<PlasmoCSUIProps> = () => {
|
||||
const [parseContent, setParseContent] = useParseMarkdown()
|
||||
const [allShowTag, setAllShowTag] = useStorage("config-allShowTag", true)
|
||||
const [showTag, setShowTag] = useStorage<boolean>("pianshen-showTag", true)
|
||||
const [cssCode, runCss] = useCssCodeHook("pianshen")
|
||||
const [content, setContent] = useEditMarkdown()
|
||||
|
||||
useMessage(async (req, res) => {
|
||||
if (req.name == "pianshen-isShow") {
|
||||
res.send({ isShow: true })
|
||||
}
|
||||
if (req.name == "pianshen-editMarkdown") {
|
||||
editMarkdown()
|
||||
}
|
||||
if (req.name == "pianshen-downloadMarkdown") {
|
||||
downloadMarkdown()
|
||||
}
|
||||
if (req.name == "pianshen-downloadHtml") {
|
||||
downloadHtml()
|
||||
}
|
||||
if (req.name == "pianshen-downloadPdf") {
|
||||
downloadPdf()
|
||||
}
|
||||
})
|
||||
|
||||
function getDescription() {
|
||||
const summary = document.querySelector<HTMLMetaElement>(
|
||||
'meta[name="description"]'
|
||||
).content
|
||||
summary && prompt("文章摘要:", summary)
|
||||
}
|
||||
|
||||
function downloadPdf() {
|
||||
const article = document.querySelector<HTMLElement>("#article_content")
|
||||
if (article) {
|
||||
Print.print(article, { title: articleTitle })
|
||||
.then(() => console.log("Printing complete"))
|
||||
.catch((error) => console.error("Printing failed:", error))
|
||||
}
|
||||
}
|
||||
|
||||
function editMarkdown() {
|
||||
const dom = document.querySelector("#article_content")
|
||||
setContent(dom, articleTitle)
|
||||
}
|
||||
|
||||
function downloadMarkdown() {
|
||||
const html = document.querySelector("#article_content")
|
||||
const markdown = turndownService.turndown(html)
|
||||
saveMarkdown(markdown, articleTitle)
|
||||
}
|
||||
|
||||
function downloadHtml() {
|
||||
const dom = document.querySelector("#article_content")
|
||||
saveHtml(dom, articleTitle)
|
||||
}
|
||||
|
||||
function parseMarkdown() {
|
||||
const dom = document.querySelector("#article_content")
|
||||
setParseContent(dom)
|
||||
}
|
||||
|
||||
return showTag && allShowTag ? (
|
||||
<ToolBox
|
||||
onGetDescription={getDescription}
|
||||
onEditMarkdown={editMarkdown}
|
||||
onDownloadMarkdown={downloadMarkdown}
|
||||
onPrint={downloadPdf}
|
||||
onParseMarkdown={parseMarkdown}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
}
|
||||
|
||||
export default PlasmoOverlay
|
||||
@@ -1,58 +1,29 @@
|
||||
import type {
|
||||
PlasmoCSConfig,
|
||||
PlasmoCSUIProps,
|
||||
PlasmoGetOverlayAnchor,
|
||||
PlasmoGetShadowHostId,
|
||||
PlasmoGetStyle
|
||||
} from "plasmo"
|
||||
import React, { type FC } from "react"
|
||||
import type { PlasmoCSConfig } from "plasmo"
|
||||
|
||||
import { useMessage } from "@plasmohq/messaging/hook"
|
||||
import { useStorage } from "@plasmohq/storage/dist/hook"
|
||||
|
||||
import TagBtnStyle from "~component/tagBtn/style"
|
||||
import Tags from "~component/ui/tags"
|
||||
import ToolBox from "~component/ui/toolBox"
|
||||
import { i18n, saveHtml, saveMarkdown } from "~tools"
|
||||
import { saveHtml, saveMarkdown } from "~tools"
|
||||
import useCssCodeHook from "~utils/cssCodeHook"
|
||||
import { useEditMarkdown } from "~utils/editMarkdownHook"
|
||||
import { useParseMarkdown } from "~utils/parseMarkdownHook"
|
||||
import { Print } from "~utils/print"
|
||||
import { useContent } from "~utils/editMarkdownHook"
|
||||
import Turndown from "~utils/turndown"
|
||||
|
||||
export const config: PlasmoCSConfig = {
|
||||
matches: ["https://*.segmentfault.com/**"]
|
||||
matches: ["https://*.segmentfault.com/*"]
|
||||
}
|
||||
|
||||
const turndownService = Turndown()
|
||||
const articleTitle = document
|
||||
.querySelector<HTMLElement>("head title")
|
||||
.innerText.trim()
|
||||
const articleTitle = document.querySelector<HTMLElement>("head title").innerText
|
||||
|
||||
const HOST_ID = "codebox-segmentfault"
|
||||
export const getShadowHostId: PlasmoGetShadowHostId = () => HOST_ID
|
||||
|
||||
export const getOverlayAnchor: PlasmoGetOverlayAnchor = async () =>
|
||||
document.querySelector(".article-wrap.container")
|
||||
|
||||
export const getStyle: PlasmoGetStyle = () => TagBtnStyle()
|
||||
|
||||
const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
const [parseContent, setParseContent] = useParseMarkdown()
|
||||
const [allShowTag, setAllShowTag] = useStorage("config-allShowTag", true)
|
||||
const [showTag, setShowTag] = useStorage<boolean>(
|
||||
"segmentfault-showTag",
|
||||
true
|
||||
)
|
||||
export default function Segmentfault() {
|
||||
const [cssCode, runCss] = useCssCodeHook("segmentfault")
|
||||
const [content, setContent] = useEditMarkdown()
|
||||
const [content, setContent] = useContent()
|
||||
|
||||
useMessage(async (req, res) => {
|
||||
if (req.name == "segmentfault-isShow") {
|
||||
res.send({ isShow: true })
|
||||
}
|
||||
if (req.name == "segmentfault-editMarkdown") {
|
||||
editMarkdown()
|
||||
setContent("article.article")
|
||||
}
|
||||
if (req.name == "segmentfault-downloadMarkdown") {
|
||||
downloadMarkdown()
|
||||
@@ -60,59 +31,18 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
if (req.name == "segmentfault-downloadHtml") {
|
||||
downloadHtml()
|
||||
}
|
||||
if (req.name == "segmentfault-downloadPdf") {
|
||||
downloadPdf()
|
||||
}
|
||||
})
|
||||
|
||||
function getDescription() {
|
||||
const summary = document.querySelector<HTMLMetaElement>(
|
||||
'meta[name="description"]'
|
||||
).content
|
||||
summary && prompt("文章摘要:", summary)
|
||||
}
|
||||
|
||||
function downloadPdf() {
|
||||
const article = document.querySelector<HTMLElement>(".container")
|
||||
if (article) {
|
||||
Print.print(article, { title: articleTitle })
|
||||
.then(() => console.log("Printing complete"))
|
||||
.catch((error) => console.error("Printing failed:", error))
|
||||
}
|
||||
}
|
||||
|
||||
function editMarkdown() {
|
||||
const dom = document.querySelector(".container")
|
||||
setContent(dom, articleTitle)
|
||||
}
|
||||
|
||||
function downloadMarkdown() {
|
||||
const html = document.querySelector(".container")
|
||||
const html = document.querySelector("article.article")
|
||||
const markdown = turndownService.turndown(html)
|
||||
saveMarkdown(markdown, articleTitle)
|
||||
}
|
||||
|
||||
function downloadHtml() {
|
||||
const dom = document.querySelector(".container")
|
||||
const dom = document.querySelector("article.article")
|
||||
saveHtml(dom, articleTitle)
|
||||
}
|
||||
|
||||
function parseMarkdown() {
|
||||
const dom = document.querySelector(".container")
|
||||
setParseContent(dom)
|
||||
}
|
||||
|
||||
return showTag && allShowTag ? (
|
||||
<ToolBox
|
||||
onGetDescription={getDescription}
|
||||
onEditMarkdown={editMarkdown}
|
||||
onDownloadMarkdown={downloadMarkdown}
|
||||
onPrint={downloadPdf}
|
||||
onParseMarkdown={parseMarkdown}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
return <div style={{ display: "none" }}></div>
|
||||
}
|
||||
|
||||
export default PlasmoOverlay
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { saveAs } from "file-saver"
|
||||
import JSZip from "jszip"
|
||||
import html2pdf from "html2pdf.js"
|
||||
import type {
|
||||
PlasmoCSConfig,
|
||||
PlasmoCSUIProps,
|
||||
@@ -7,154 +6,62 @@ import type {
|
||||
PlasmoGetShadowHostId,
|
||||
PlasmoGetStyle
|
||||
} from "plasmo"
|
||||
import qrcodeUrl from "raw:~/public/wx/gzh.jpg"
|
||||
import React, { useEffect, useState, type FC } from "react"
|
||||
import { useEffect, type FC } from "react"
|
||||
|
||||
import { useMessage } from "@plasmohq/messaging/hook"
|
||||
import { useStorage } from "@plasmohq/storage/dist/hook"
|
||||
|
||||
import { saveHtml, saveMarkdown } from "~tools"
|
||||
import { i18n, saveHtml, saveMarkdown } from "~tools"
|
||||
import useCssCodeHook from "~utils/cssCodeHook"
|
||||
import { useEditMarkdown } from "~utils/editMarkdownHook"
|
||||
import makerQRPost from "~utils/makerQRPost"
|
||||
import { useParseMarkdown } from "~utils/parseMarkdownHook"
|
||||
import { Print } from "~utils/print"
|
||||
import { useContent } from "~utils/editMarkdownHook"
|
||||
import Turndown from "~utils/turndown"
|
||||
|
||||
export const config: PlasmoCSConfig = {
|
||||
matches: ["https://mp.weixin.qq.com/s/*", "https://mp.weixin.qq.com/s?src=*"]
|
||||
matches: ["https://mp.weixin.qq.com/s/*"]
|
||||
}
|
||||
|
||||
const turndownService = Turndown()
|
||||
const articleTitle = document
|
||||
.querySelector<HTMLMetaElement>('meta[property="og:title"]')
|
||||
.content.trim()
|
||||
const articleTitle = document.querySelector<HTMLElement>("head title").innerText
|
||||
|
||||
const HOST_ID = "codebox-weixin"
|
||||
export const getShadowHostId: PlasmoGetShadowHostId = () => HOST_ID
|
||||
|
||||
export const getOverlayAnchor: PlasmoGetOverlayAnchor = async () =>
|
||||
document.querySelector("#activity-detail")
|
||||
document.querySelector("#img-content .rich_media_title")
|
||||
|
||||
const formatLimit = 5
|
||||
const formatList = new WeakMap()
|
||||
const urlReg =
|
||||
/\b((?:https?:\/\/)?(?![\d-]+\.[\d-]+)([\w-]+(\.[\w-]+)+[\S^\"\'\[\]\{\}\>\<]*))/gi
|
||||
const ignoreTags = [
|
||||
"SCRIPT",
|
||||
"STYLE",
|
||||
"A",
|
||||
"TEXTAREA",
|
||||
"NOSCRIPT",
|
||||
"CODE",
|
||||
"TITLE"
|
||||
]
|
||||
const formatLinks = (target: Node, nodes: NodeList) => {
|
||||
if (
|
||||
!(target instanceof HTMLElement) ||
|
||||
ignoreTags.includes(target.nodeName) ||
|
||||
target.translate === false
|
||||
)
|
||||
return
|
||||
|
||||
const formatTimes = formatList.get(target) || 0
|
||||
if (formatTimes > formatLimit) return
|
||||
|
||||
let modified = false
|
||||
nodes.forEach((node: any) => {
|
||||
if (node.nodeType === Node.TEXT_NODE && node.textContent.match(urlReg)) {
|
||||
const newContent = node.textContent.replace(
|
||||
urlReg,
|
||||
(match) =>
|
||||
`<a href="${match.startsWith("http") ? match : "http://" + match}"
|
||||
target="_blank"
|
||||
style="color: #576b95; text-decoration: none;">
|
||||
${match}
|
||||
</a>`
|
||||
)
|
||||
const wrapper = document.createElement("span")
|
||||
wrapper.innerHTML = newContent
|
||||
node.replaceWith(wrapper)
|
||||
modified = true
|
||||
}
|
||||
})
|
||||
|
||||
if (modified) {
|
||||
formatList.set(target, formatTimes + 1)
|
||||
}
|
||||
}
|
||||
|
||||
const queryChildElements = (element: Node) => {
|
||||
if (element instanceof Element) {
|
||||
;[...element.querySelectorAll("*")].forEach((child) =>
|
||||
formatLinks(child, child.childNodes)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const createLinkObserver = () => {
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
mutations.forEach((mutation) => {
|
||||
formatLinks(mutation.target, mutation.addedNodes)
|
||||
mutation.addedNodes.forEach((node) => queryChildElements(node))
|
||||
})
|
||||
})
|
||||
|
||||
return observer
|
||||
}
|
||||
|
||||
const observer = createLinkObserver()
|
||||
observer.observe(document, {
|
||||
subtree: true,
|
||||
childList: true,
|
||||
characterData: true
|
||||
})
|
||||
|
||||
queryChildElements(document.documentElement)
|
||||
|
||||
const style = {
|
||||
box: {
|
||||
position: "fixed" as const,
|
||||
border: "1px solid #D9DADC",
|
||||
left: "25px",
|
||||
top: "25px",
|
||||
width: "140px",
|
||||
padding: "16px",
|
||||
cursor: "pointer"
|
||||
},
|
||||
close: {
|
||||
position: "absolute" as const,
|
||||
top: "-5px",
|
||||
right: "0px",
|
||||
background: "none",
|
||||
border: "none",
|
||||
fontSize: "1.5rem",
|
||||
cursor: "pointer",
|
||||
padding: "0.5rem"
|
||||
},
|
||||
img: {
|
||||
width: "100%"
|
||||
},
|
||||
item: {
|
||||
color: "#000000"
|
||||
export const getStyle: PlasmoGetStyle = () => {
|
||||
const style = document.createElement("style")
|
||||
style.textContent = `
|
||||
.codebox-tagBtn {
|
||||
height: 28px;
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
color: #1e80ff;
|
||||
width: 66px;
|
||||
background: transparent;
|
||||
border-radius: 5px;
|
||||
justify-content: space-between;
|
||||
padding: 0 8px;
|
||||
margin-top: -20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
`
|
||||
return style
|
||||
}
|
||||
|
||||
const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
const [parseContent, setParseContent] = useParseMarkdown()
|
||||
const [allShowTag, setAllShowTag] = useStorage("config-allShowTag", true)
|
||||
const [showTag, setShowTag] = useStorage<boolean>("weixin-showTag", true)
|
||||
const [showTag, setShowTag] = useStorage<boolean>("weixin-showTag")
|
||||
const [cssCode, runCss] = useCssCodeHook("weixin")
|
||||
const [history, setHistory] = useStorage<any[]>("codebox-history")
|
||||
const [content, setContent] = useEditMarkdown()
|
||||
const [isShow, setIsShow] = useState(true)
|
||||
const [content, setContent] = useContent()
|
||||
|
||||
useMessage(async (req: any, res: any) => {
|
||||
useMessage(async (req, res) => {
|
||||
if (req.name == "weixin-isShow") {
|
||||
res.send({ isShow: true })
|
||||
}
|
||||
if (req.name == "weixin-editMarkdown") {
|
||||
editMarkdown()
|
||||
setContent("#img-content")
|
||||
}
|
||||
if (req.name == "weixin-downloadMarkdown") {
|
||||
downloadMarkdown()
|
||||
@@ -165,98 +72,147 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
if (req.name == "weixin-downloadPdf") {
|
||||
downloadPdf()
|
||||
}
|
||||
if (req.name == "weixin-downloadImages") {
|
||||
await downloadImages(req.body?.onProgress)
|
||||
}
|
||||
if (req.name == "weixin-getThumbMedia") {
|
||||
getThumbMedia()
|
||||
}
|
||||
})
|
||||
|
||||
function getThumbMedia() {
|
||||
const thumbMediaUrl = document.querySelector<HTMLMetaElement>(
|
||||
'meta[property="og:image"]'
|
||||
).content
|
||||
thumbMediaUrl && window.open(thumbMediaUrl)
|
||||
}
|
||||
|
||||
function getDescription() {
|
||||
const summary = document.querySelector<HTMLMetaElement>(
|
||||
'meta[name="description"]'
|
||||
).content
|
||||
summary && prompt("文章摘要:", summary)
|
||||
}
|
||||
|
||||
async function downloadImages(
|
||||
onProgress?: (current: number, total: number) => void
|
||||
) {
|
||||
const article = document.querySelector("#js_content")
|
||||
if (!article) return
|
||||
|
||||
const images = Array.from(article.getElementsByTagName("img"))
|
||||
const imageUrls = images
|
||||
.map((img) => img.dataset.src || img.src)
|
||||
.filter((url) => url)
|
||||
.map((url) =>
|
||||
url.replace(
|
||||
"//res.wx.qq.com/mmbizwap",
|
||||
"https://res.wx.qq.com/mmbizwap"
|
||||
)
|
||||
)
|
||||
|
||||
const zip = new JSZip()
|
||||
const title = document.title.trim()
|
||||
const total = imageUrls.length
|
||||
|
||||
for (let i = 0; i < imageUrls.length; i++) {
|
||||
try {
|
||||
const response = await fetch(imageUrls[i])
|
||||
const blob = await response.blob()
|
||||
|
||||
let ext = ".jpg"
|
||||
if (
|
||||
imageUrls[i].includes("wx_fmt=gif") ||
|
||||
imageUrls[i].includes("mmbiz_gif")
|
||||
) {
|
||||
ext = ".gif"
|
||||
} else if (
|
||||
imageUrls[i].includes("wx_fmt=png") ||
|
||||
imageUrls[i].includes("mmbiz_png")
|
||||
) {
|
||||
ext = ".png"
|
||||
} else if (
|
||||
imageUrls[i].includes("wx_fmt=bmp") ||
|
||||
imageUrls[i].includes("mmbiz_bmp")
|
||||
) {
|
||||
ext = ".bmp"
|
||||
}
|
||||
|
||||
zip.file(`${title}-${i}${ext}`, blob)
|
||||
|
||||
if (onProgress) {
|
||||
onProgress(i + 1, total)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Failed to download image ${i}:`, error)
|
||||
}
|
||||
}
|
||||
|
||||
const content = await zip.generateAsync({ type: "blob" })
|
||||
saveAs(content, `${title}-images.zip`)
|
||||
}
|
||||
console.log(777, html2pdf)
|
||||
|
||||
function downloadPdf() {
|
||||
const article = document.querySelector<HTMLElement>("#img-content")
|
||||
if (article) {
|
||||
Print.print(article, { title: articleTitle })
|
||||
.then(() => console.log("Printing complete"))
|
||||
.catch((error) => console.error("Printing failed:", error))
|
||||
}
|
||||
}
|
||||
// 获取文章内容和标题、作者、时间等元信息
|
||||
var article = document.querySelector<HTMLElement>(".rich_media_content")
|
||||
var title = document.querySelector<HTMLElement>(".rich_media_title")
|
||||
var author = document.querySelector<HTMLElement>(".weui-wa-hotarea") // 文章作者
|
||||
var publishTime = document.querySelector<HTMLElement>("#publish_time") // 文章时间
|
||||
|
||||
function editMarkdown() {
|
||||
const dom = document.querySelector("#img-content")
|
||||
setContent(dom, articleTitle)
|
||||
if (article) {
|
||||
// 创建一个容器用于添加元信息
|
||||
var metaInfoDiv = document.createElement("div")
|
||||
metaInfoDiv.style.marginBottom = "20px"
|
||||
metaInfoDiv.style.borderBottom = "1px solid #eee"
|
||||
metaInfoDiv.style.paddingBottom = "15px"
|
||||
|
||||
// 标题
|
||||
var titleElement = document.createElement("h1")
|
||||
titleElement.innerText = title ? title?.innerText.trim() : "未命名文章"
|
||||
titleElement.style.fontSize = "24px"
|
||||
titleElement.style.marginBottom = "10px"
|
||||
metaInfoDiv.appendChild(titleElement)
|
||||
|
||||
// 作者
|
||||
if (author) {
|
||||
var authorElement = document.createElement("p")
|
||||
authorElement.innerText = "作者: " + author.innerText.trim()
|
||||
authorElement.style.fontSize = "14px"
|
||||
authorElement.style.margin = "5px 0"
|
||||
metaInfoDiv.appendChild(authorElement)
|
||||
}
|
||||
|
||||
// 时间
|
||||
if (publishTime) {
|
||||
var timeElement = document.createElement("p")
|
||||
timeElement.innerText = "发布时间: " + publishTime.innerText.trim()
|
||||
timeElement.style.fontSize = "14px"
|
||||
timeElement.style.margin = "5px 0"
|
||||
metaInfoDiv.appendChild(timeElement)
|
||||
}
|
||||
|
||||
// 将元信息插入到文章内容的顶部
|
||||
article.insertBefore(metaInfoDiv, article.firstChild)
|
||||
|
||||
// 添加防止图片分页的CSS样式
|
||||
var style = document.createElement("style")
|
||||
style.innerHTML = `
|
||||
.rich_media_content img {
|
||||
page-break-inside: avoid;
|
||||
break-inside: avoid;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
.rich_media_content p, .rich_media_content div {
|
||||
page-break-inside: avoid;
|
||||
break-inside: avoid;
|
||||
}
|
||||
`
|
||||
document.head.appendChild(style)
|
||||
|
||||
// 确保所有图片加载完成
|
||||
let images = article.querySelectorAll("img")
|
||||
let imagePromises = []
|
||||
|
||||
images.forEach(function (img) {
|
||||
// 处理懒加载的图片,确保图片的真实 URL 被加载
|
||||
if (img.dataset && img.dataset.src) {
|
||||
img.src = img.dataset.src
|
||||
}
|
||||
|
||||
// 通过跨域获取图片,并将图片转换为 base64 格式
|
||||
imagePromises.push(
|
||||
new Promise(function (resolve) {
|
||||
var imgElement = new Image()
|
||||
imgElement.crossOrigin = "Anonymous"
|
||||
imgElement.src = img.src
|
||||
imgElement.onload = function () {
|
||||
var canvas = document.createElement("canvas")
|
||||
canvas.width = imgElement.width
|
||||
canvas.height = imgElement.height
|
||||
var ctx = canvas.getContext("2d")
|
||||
ctx.drawImage(imgElement, 0, 0)
|
||||
img.src = canvas.toDataURL("image/jpeg") // 使用JPEG格式并压缩质量到70%
|
||||
resolve()
|
||||
}
|
||||
imgElement.onerror = resolve // 即使图片加载失败,继续处理
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
// 确保图片加载完成后再导出PDF
|
||||
Promise.all(imagePromises)
|
||||
.then(function () {
|
||||
// 使用文章标题作为文件名
|
||||
var fileName = title
|
||||
? title.innerText.trim() + ".pdf"
|
||||
: "WeChat_Article.pdf"
|
||||
|
||||
var opt = {
|
||||
margin: 0.5,
|
||||
filename: fileName,
|
||||
image: {
|
||||
type: "jpeg",
|
||||
quality: 1 // 降低图片质量以减小PDF体积
|
||||
},
|
||||
html2canvas: {
|
||||
scale: 1.5, // 降低渲染比例以减小PDF体积
|
||||
useCORS: true, // 允许跨域图片
|
||||
logging: false // 关闭日志
|
||||
// 可以根据需要添加其他html2canvas选项
|
||||
},
|
||||
jsPDF: {
|
||||
unit: "in",
|
||||
format: "a4", // 使用A4格式,比letter更常用且体积可能更小
|
||||
orientation: "portrait"
|
||||
},
|
||||
pagebreak: {
|
||||
mode: ["avoid-all", "css", "legacy"]
|
||||
} // 遵循CSS中的page-break规则
|
||||
}
|
||||
|
||||
// 使用 html2pdf 将文章内容导出为 PDF
|
||||
html2pdf()
|
||||
.from(article)
|
||||
.set(opt)
|
||||
.save()
|
||||
.then(function () {})
|
||||
.catch(function (error) {
|
||||
alert("导出过程中出现问题: " + error.message)
|
||||
console.log(error)
|
||||
})
|
||||
})
|
||||
.catch(function (error) {
|
||||
alert("处理图片时出现问题: " + error.message)
|
||||
console.log(error)
|
||||
})
|
||||
} else {
|
||||
alert("未找到文章内容")
|
||||
}
|
||||
}
|
||||
|
||||
function downloadMarkdown() {
|
||||
@@ -270,62 +226,24 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
saveHtml(dom, articleTitle)
|
||||
}
|
||||
|
||||
function parseMarkdown() {
|
||||
const dom = document.querySelector("#img-content")
|
||||
setParseContent(dom)
|
||||
function handleEdit() {
|
||||
setContent("#img-content")
|
||||
}
|
||||
|
||||
function onClose() {
|
||||
setIsShow(false)
|
||||
function handleDownload() {
|
||||
const html = document.querySelector("#img-content")
|
||||
const markdown = turndownService.turndown(html)
|
||||
saveMarkdown(markdown, articleTitle)
|
||||
}
|
||||
|
||||
return showTag && isShow && allShowTag ? (
|
||||
<div id="ws_cmbm" className="ws_cmbmc" style={style.box}>
|
||||
<button style={style.close} onClick={onClose} aria-label="Close">
|
||||
×
|
||||
</button>
|
||||
<img src={qrcodeUrl} alt="qrcodeUrl" style={style.img} />
|
||||
<div style={style.item}>
|
||||
<a onClick={getThumbMedia}>文章封面</a>
|
||||
</div>
|
||||
<div style={style.item}>
|
||||
<a onClick={getDescription}>文章摘要</a>
|
||||
</div>
|
||||
<div style={style.item}>
|
||||
<a
|
||||
style={{ color: "#000" }}
|
||||
href="javascript:(function(){const rules={'mp.weixin.qq.com':{testReg:/^http(?:s)?:\/\/mp\.weixin\.qq\.com\/s\?.*$/i,query:['__biz','idx','mid','sn','src','timestamp','ver','signature']},other:{testReg:/^(http(?:s)?:\/\/[^?#]*)[?#].*$/i,query:['id','tid','uid','q','wd','query','keyword','keywords']}};const pureUrl=function(url=window.location.href){const hash=url.replace(/^[^#]*(#.*)?$/,'$1'),base=url.replace(/(\?|#).*$/,'');let pureUrl=url;const getQueryString=function(key){let ret=url.match(new RegExp('(?:\\?|&)('+key+'=[^?#&]*)','i'));return null===ret?'':ret[1]},methods={decodeUrl:function(url){return decodeURIComponent(url)}};for(let i in rules){let rule=rules[i],reg=rule.testReg,replace=rule.replace;if(reg.test(url)){let newQuerys='';void 0!==rule.query&&rule.query.length>0&&rule.query.map(query=>{const ret=getQueryString(query);''!==ret&&(newQuerys+=(newQuerys.length?'&':'?')+ret)}),newQuerys+=void 0!==rule.hash&&rule.hash?hash:'',pureUrl=(void 0===replace?base:url.replace(reg,replace))+newQuerys,void 0!==rule.methods&&rule.methods.length>0&&rule.methods.map(methodName=>{pureUrl=methods[methodName](pureUrl)});break}}return pureUrl}();let newnode=document.createElement('input');newnode.id='pure-url-for-copy',newnode.value=pureUrl,document.body.appendChild(newnode);let copyinput=document.getElementById('pure-url-for-copy');copyinput.select();try{document.execCommand('copy');window.location.href===pureUrl?window.location.reload():window.location.href=pureUrl}catch(err){null!=prompt('%E5%87%80%E5%8C%96%E5%90%8E%E7%9A%84%E7%BD%91%E5%9D%80%E6%98%AF%EF%BC%9A',pureUrl)&&(window.location.href=pureUrl)}document.body.removeChild(copyinput)})();">
|
||||
净化链接
|
||||
</a>
|
||||
</div>
|
||||
<div style={style.item}>
|
||||
<a
|
||||
style={{ color: "#000" }}
|
||||
href="javascript:(function(){prompt( '原始链接:', 'https://mp.weixin.qq.com/s?__biz='+biz+'&idx=1&mid='+mid+'&sn='+sn)})();">
|
||||
原始链接
|
||||
</a>
|
||||
</div>
|
||||
<div style={style.item}>
|
||||
<a onClick={editMarkdown}>编辑markdown</a>
|
||||
</div>
|
||||
<div style={style.item}>
|
||||
<a onClick={downloadMarkdown}>下载markdown</a>
|
||||
</div>
|
||||
<div style={style.item}>
|
||||
<a onClick={downloadPdf}>下载PDF</a>
|
||||
</div>
|
||||
<div style={style.item}>
|
||||
<a onClick={parseMarkdown}>解析markdown</a>
|
||||
</div>
|
||||
<div style={style.item}>
|
||||
<a onClick={() => downloadImages()}>下载所有图片</a>
|
||||
</div>
|
||||
<div style={style.item}>
|
||||
<a onClick={() => makerQRPost()}>生成海报</a>
|
||||
</div>
|
||||
<a style={style.item} href="https://www.code-box.fun" target="_blank">
|
||||
帮助
|
||||
</a>
|
||||
function closeTag() {
|
||||
setShowTag(false)
|
||||
}
|
||||
|
||||
return showTag ? (
|
||||
<div className="codebox-tagBtn">
|
||||
<div onClick={handleEdit}>{i18n("edit")}</div>
|
||||
<div onClick={handleDownload}>{i18n("download")}</div>
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
|
||||
@@ -1,22 +1,13 @@
|
||||
import type {
|
||||
PlasmoCSConfig,
|
||||
PlasmoCSUIProps,
|
||||
PlasmoGetOverlayAnchor,
|
||||
PlasmoGetShadowHostId
|
||||
} from "plasmo"
|
||||
import qrcodeUrl from "raw:~/public/wx/gzh.jpg"
|
||||
import React, { useEffect, useRef, useState, type FC } from "react"
|
||||
import type { PlasmoCSConfig } from "plasmo"
|
||||
import { useEffect, useRef } from "react"
|
||||
import { v4 as uuidv4 } from "uuid"
|
||||
|
||||
import { useMessage } from "@plasmohq/messaging/hook"
|
||||
import { useStorage } from "@plasmohq/storage/hook"
|
||||
|
||||
import ToolBox from "~component/ui/toolBox"
|
||||
import { addCss, saveHtml, saveMarkdown } from "~tools"
|
||||
import useCssCodeHook from "~utils/cssCodeHook"
|
||||
import { useEditMarkdown } from "~utils/editMarkdownHook"
|
||||
import { useParseMarkdown } from "~utils/parseMarkdownHook"
|
||||
import { Print } from "~utils/print"
|
||||
import { useContent } from "~utils/editMarkdownHook"
|
||||
import Turndown from "~utils/turndown"
|
||||
|
||||
export const config: PlasmoCSConfig = {
|
||||
@@ -24,58 +15,16 @@ export const config: PlasmoCSConfig = {
|
||||
}
|
||||
|
||||
const turndownService = Turndown()
|
||||
const articleTitle = document
|
||||
.querySelector<HTMLElement>("head title")
|
||||
.innerText.trim()
|
||||
const articleTitle = document.querySelector<HTMLElement>("head title").innerText
|
||||
|
||||
const HOST_ID = "codebox-zhihu"
|
||||
export const getShadowHostId: PlasmoGetShadowHostId = () => HOST_ID
|
||||
|
||||
export const getOverlayAnchor: PlasmoGetOverlayAnchor = async () =>
|
||||
document.querySelector("article.Post-Main")
|
||||
|
||||
const style = {
|
||||
box: {
|
||||
position: "fixed" as const,
|
||||
border: "1px solid #D9DADC",
|
||||
left: "25px",
|
||||
top: "85px",
|
||||
width: "140px",
|
||||
padding: "16px",
|
||||
cursor: "pointer"
|
||||
},
|
||||
close: {
|
||||
position: "absolute" as const,
|
||||
top: "-5px",
|
||||
right: "0px",
|
||||
background: "none",
|
||||
border: "none",
|
||||
fontSize: "1.5rem",
|
||||
cursor: "pointer",
|
||||
padding: "0.5rem"
|
||||
},
|
||||
img: {
|
||||
width: "100%"
|
||||
},
|
||||
item: {
|
||||
color: "#000000",
|
||||
fontSize: "1rem",
|
||||
marginBottom: "3px"
|
||||
}
|
||||
}
|
||||
|
||||
const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
const [parseContent, setParseContent] = useParseMarkdown()
|
||||
const [allShowTag, setAllShowTag] = useStorage("config-allShowTag", true)
|
||||
const [showTag, setShowTag] = useStorage<boolean>("zhihu-showTag", true)
|
||||
export default function zhihu() {
|
||||
const [cssCode, runCss] = useCssCodeHook("zhihu")
|
||||
const [closeLoginModal] = useStorage<boolean>("zhihu-closeLoginModal")
|
||||
const [copyCode] = useStorage<boolean>("zhihu-copyCode")
|
||||
const [autoOpenCode] = useStorage<boolean>("zhihu-autoOpenCode")
|
||||
const [history, setHistory] = useStorage<any[]>("codebox-history")
|
||||
const [closeLog] = useStorage("config-closeLog", true)
|
||||
const [content, setContent] = useEditMarkdown()
|
||||
const [isShow, setIsShow] = useState(true)
|
||||
const [content, setContent] = useContent()
|
||||
|
||||
useEffect(() => {
|
||||
closeLog ||
|
||||
@@ -90,7 +39,7 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
res.send({ isShow: true })
|
||||
}
|
||||
if (req.name == "zhihu-editMarkdown") {
|
||||
editMarkdown()
|
||||
setContent("article.Post-Main")
|
||||
}
|
||||
if (req.name == "zhihu-downloadMarkdown") {
|
||||
downloadMarkdown()
|
||||
@@ -98,9 +47,6 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
if (req.name == "zhihu-downloadHtml") {
|
||||
downloadHtml()
|
||||
}
|
||||
if (req.name == "zhihu-downloadPdf") {
|
||||
downloadPdf()
|
||||
}
|
||||
})
|
||||
|
||||
// 功能一: 修改复制按钮,支持一键复制
|
||||
@@ -214,13 +160,6 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
}
|
||||
}
|
||||
|
||||
function getDescription() {
|
||||
const summary = document.querySelector<HTMLMetaElement>(
|
||||
'meta[name="description"]'
|
||||
).content
|
||||
summary && prompt("文章摘要:", summary)
|
||||
}
|
||||
|
||||
function removeRichContentCollapsed() {
|
||||
const isCollapseds = document.querySelectorAll(".RichContent.is-collapsed")
|
||||
if (isCollapseds.length > 0) {
|
||||
@@ -230,20 +169,6 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
}
|
||||
}
|
||||
|
||||
function downloadPdf() {
|
||||
const article = document.querySelector<HTMLElement>("article.Post-Main")
|
||||
if (article) {
|
||||
Print.print(article, { title: articleTitle })
|
||||
.then(() => console.log("Printing complete"))
|
||||
.catch((error) => console.error("Printing failed:", error))
|
||||
}
|
||||
}
|
||||
|
||||
function editMarkdown() {
|
||||
const dom = document.querySelector("article.Post-Main")
|
||||
setContent(dom, articleTitle)
|
||||
}
|
||||
|
||||
function downloadMarkdown() {
|
||||
const html = document.querySelector("article.Post-Main")
|
||||
const markdown = turndownService.turndown(html)
|
||||
@@ -255,26 +180,5 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
saveHtml(dom, articleTitle)
|
||||
}
|
||||
|
||||
function parseMarkdown() {
|
||||
const dom = document.querySelector("article.Post-Main")
|
||||
setParseContent(dom)
|
||||
}
|
||||
|
||||
function onClose() {
|
||||
setIsShow(false)
|
||||
}
|
||||
|
||||
return showTag && isShow && allShowTag ? (
|
||||
<ToolBox
|
||||
onGetDescription={getDescription}
|
||||
onEditMarkdown={editMarkdown}
|
||||
onDownloadMarkdown={downloadMarkdown}
|
||||
onPrint={downloadPdf}
|
||||
onParseMarkdown={parseMarkdown}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
return <div style={{ display: "none" }}></div>
|
||||
}
|
||||
|
||||
export default PlasmoOverlay
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
width: 190px;
|
||||
margin: 0 auto;
|
||||
padding: 5px 8px;
|
||||
max-height: 590px;
|
||||
}
|
||||
|
||||
.App-header .title {
|
||||
@@ -29,18 +28,11 @@
|
||||
}
|
||||
|
||||
.App-link {
|
||||
margin-top: 5px;
|
||||
margin-top: 10px;
|
||||
margin-left: 5px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.App-link .item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 5px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.popup .App-body {
|
||||
max-height: 450px;
|
||||
overflow-y: scroll;
|
||||
|
||||
@@ -131,9 +131,6 @@
|
||||
"zhihuAutoOpenCode": {
|
||||
"message": "Auto Open Code"
|
||||
},
|
||||
"getDescription": {
|
||||
"message": "Get Description"
|
||||
},
|
||||
"edit": {
|
||||
"message": "Edit"
|
||||
},
|
||||
@@ -146,9 +143,6 @@
|
||||
"downloadMarkdown": {
|
||||
"message": "Download Markdown"
|
||||
},
|
||||
"parseMarkdown": {
|
||||
"message": "Parse Markdown"
|
||||
},
|
||||
"downloadHtml": {
|
||||
"message": "Download HTML"
|
||||
},
|
||||
@@ -158,21 +152,9 @@
|
||||
"downloadImg": {
|
||||
"message": "Download Image"
|
||||
},
|
||||
"downloadAllImg": {
|
||||
"message": "Download All Image"
|
||||
},
|
||||
"getArticle": {
|
||||
"message": "Get All Article"
|
||||
},
|
||||
"downloading": {
|
||||
"message": "Downloading"
|
||||
},
|
||||
"copyCode": {
|
||||
"message": "Copy Code"
|
||||
},
|
||||
"parse": {
|
||||
"message": "parse"
|
||||
},
|
||||
"copy": {
|
||||
"message": "copy"
|
||||
},
|
||||
@@ -182,9 +164,6 @@
|
||||
"showTag": {
|
||||
"message": "Show Tag"
|
||||
},
|
||||
"allShowTag": {
|
||||
"message": "All Tag"
|
||||
},
|
||||
"code": {
|
||||
"message": "Code"
|
||||
},
|
||||
@@ -200,31 +179,7 @@
|
||||
"weixinConfig": {
|
||||
"message": "Wechat Config"
|
||||
},
|
||||
"paywallbusterConfig": {
|
||||
"message": "Paywallbuster Config"
|
||||
},
|
||||
"360docConfig": {
|
||||
"message": "360doc Config"
|
||||
},
|
||||
"pianshenConfig": {
|
||||
"message": "PianShen Config"
|
||||
},
|
||||
"luoguConfig": {
|
||||
"message": "LuoGu Config"
|
||||
},
|
||||
"fullPageScreenshot": {
|
||||
"message": "Full Page Screenshot"
|
||||
},
|
||||
"getThumbMedia": {
|
||||
"message": "get Thumb Media"
|
||||
},
|
||||
"getMediaResources": {
|
||||
"message": "get Media Resources"
|
||||
},
|
||||
"copyURL": {
|
||||
"message": "copy URL"
|
||||
},
|
||||
"makerQRPost": {
|
||||
"message": "maker Post Image"
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
"message": "实现一键下载文章成html或markdown文件;无需登录一键复制代码;支持选中代码;或者代码右上角按钮的一键复制;解除关注博主即可阅读全文提示;去除登录弹窗;去除跳转APP弹窗;页面自定义样式."
|
||||
},
|
||||
"popupDescription": {
|
||||
"message": "免登录一键复制代码/下载文章"
|
||||
"message": "免登录一键复制代码"
|
||||
},
|
||||
"history": {
|
||||
"message": "历史记录"
|
||||
@@ -131,30 +131,18 @@
|
||||
"zhihuAutoOpenCode": {
|
||||
"message": "自动展开全文"
|
||||
},
|
||||
"parse": {
|
||||
"message": "解析"
|
||||
},
|
||||
"edit": {
|
||||
"message": "编辑"
|
||||
},
|
||||
"download": {
|
||||
"message": "下载"
|
||||
},
|
||||
"print": {
|
||||
"message": "打印"
|
||||
},
|
||||
"getDescription": {
|
||||
"message": "文章摘要"
|
||||
},
|
||||
"editMarkdown": {
|
||||
"message": "编辑 Markdown"
|
||||
},
|
||||
"downloadMarkdown": {
|
||||
"message": "下载 Markdown"
|
||||
},
|
||||
"parseMarkdown": {
|
||||
"message": "解析 Markdown"
|
||||
},
|
||||
"downloadHtml": {
|
||||
"message": "下载 HTML"
|
||||
},
|
||||
@@ -164,15 +152,6 @@
|
||||
"downloadImg": {
|
||||
"message": "下载图片"
|
||||
},
|
||||
"downloadAllImg": {
|
||||
"message": "下载所有图片"
|
||||
},
|
||||
"getArticle": {
|
||||
"message": "获取全文"
|
||||
},
|
||||
"downloading": {
|
||||
"message": "正在下载"
|
||||
},
|
||||
"copyCode": {
|
||||
"message": "一键复制代码"
|
||||
},
|
||||
@@ -185,9 +164,6 @@
|
||||
"showTag": {
|
||||
"message": "显示标签"
|
||||
},
|
||||
"allShowTag": {
|
||||
"message": "所有标签"
|
||||
},
|
||||
"code": {
|
||||
"message": "代码"
|
||||
},
|
||||
@@ -203,31 +179,7 @@
|
||||
"weixinConfig": {
|
||||
"message": "微信设置"
|
||||
},
|
||||
"paywallbusterConfig": {
|
||||
"message": "paywallbuster设置"
|
||||
},
|
||||
"360docConfig": {
|
||||
"message": "360doc设置"
|
||||
},
|
||||
"pianshenConfig": {
|
||||
"message": "pianshen设置"
|
||||
},
|
||||
"luoguConfig": {
|
||||
"message": "洛谷设置"
|
||||
},
|
||||
"fullPageScreenshot": {
|
||||
"message": "全页面截图"
|
||||
},
|
||||
"getThumbMedia": {
|
||||
"message": "获取封面"
|
||||
},
|
||||
"getMediaResources": {
|
||||
"message": "复制资源"
|
||||
},
|
||||
"copyURL": {
|
||||
"message": "复制URL"
|
||||
},
|
||||
"makerQRPost": {
|
||||
"message": "生成海报"
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "code-box",
|
||||
"displayName": "__MSG_extensionName__",
|
||||
"version": "1.3.5",
|
||||
"version": "0.9.15",
|
||||
"description": "__MSG_extensionDescription__",
|
||||
"author": "027xiguapi. <458813868@qq.com>",
|
||||
"scripts": {
|
||||
"dev": "plasmo dev",
|
||||
"build": "plasmo build --zip",
|
||||
"build:firefox": "plasmo build --zip --target=firefox-mv3",
|
||||
"build:firefox": "plasmo build --no-minify --no-hoist --zip --target=firefox-mv3",
|
||||
"package": "plasmo package",
|
||||
"clean": "rimraf build"
|
||||
},
|
||||
@@ -22,19 +22,20 @@
|
||||
"dependencies": {
|
||||
"@ant-design/cssinjs": "^1.21.1",
|
||||
"@ant-design/icons": "^5.5.1",
|
||||
"@dnd-kit/core": "^6.1.0",
|
||||
"@dnd-kit/sortable": "^8.0.0",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"@joplin/turndown": "^4.0.74",
|
||||
"@joplin/turndown-plugin-gfm": "^1.0.56",
|
||||
"@plasmohq/messaging": "^0.6.2",
|
||||
"@plasmohq/storage": "^1.11.0",
|
||||
"antd": "^5.21.1",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dayjs": "^1.11.12",
|
||||
"file-saver": "^2.0.5",
|
||||
"html2canvas": "^1.4.1",
|
||||
"html2pdf.js": "^0.10.2",
|
||||
"jssha": "^3.3.1",
|
||||
"jszip": "^3.10.1",
|
||||
"plasmo": "0.90.3",
|
||||
"qrcode": "^1.5.4",
|
||||
"plasmo": "0.89.4",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"uuid": "^10.0.0"
|
||||
@@ -49,20 +50,19 @@
|
||||
"postcss-modules": "^4.3.0",
|
||||
"prettier": "3.2.4",
|
||||
"sass": "^1.77.8",
|
||||
"sharp": "^0.33.5",
|
||||
"sharp": "^0.33.4",
|
||||
"typescript": "5.3.3"
|
||||
},
|
||||
"manifest": {
|
||||
"name": "__MSG_extensionName__",
|
||||
"default_locale": "en",
|
||||
"default_locale": "zh_CN",
|
||||
"browser_specific_settings": {
|
||||
"gecko": {
|
||||
"id": "$PLASMO_PUBLIC_FIREFOX_EXT_ID"
|
||||
}
|
||||
},
|
||||
"permissions": [
|
||||
"activeTab",
|
||||
"downloads"
|
||||
"activeTab"
|
||||
],
|
||||
"host_permissions": [
|
||||
"https://*/*"
|
||||
@@ -70,5 +70,9 @@
|
||||
"omnibox": {
|
||||
"keyword": "copy"
|
||||
}
|
||||
},
|
||||
"pnpm": {
|
||||
"patchedDependencies": {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,22 +4,14 @@ import { i18n } from "~tools"
|
||||
|
||||
import "~index.css"
|
||||
|
||||
import { useEffect, useState } from "react"
|
||||
|
||||
import { sendToBackground } from "@plasmohq/messaging"
|
||||
|
||||
export default function IndexPopup() {
|
||||
const [sidePanel, setSidePanel] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
hanleOpenSidePanel(sidePanel)
|
||||
}, [sidePanel])
|
||||
|
||||
function hanleOpenSidePanel(active) {
|
||||
function hanleOpenSidePanel() {
|
||||
sendToBackground({
|
||||
name: "sidepanel",
|
||||
body: {
|
||||
active: active
|
||||
active: true
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -36,16 +28,9 @@ export default function IndexPopup() {
|
||||
</div>
|
||||
<div className="App-link">
|
||||
<div className="item">
|
||||
<span>{i18n("sidePanel")}</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="sidePanel"
|
||||
name="sidePanel"
|
||||
className="codebox-offscreen"
|
||||
checked={sidePanel}
|
||||
onChange={(e) => setSidePanel(e.target.checked)}
|
||||
/>
|
||||
<label htmlFor="sidePanel" className="codebox-switch"></label>
|
||||
<a className="btn" href="#" onClick={hanleOpenSidePanel}>
|
||||
{i18n("sidePanel")}😀
|
||||
</a>
|
||||
</div>
|
||||
<div className="item">
|
||||
<a
|
||||
@@ -68,7 +53,7 @@ export default function IndexPopup() {
|
||||
<div>
|
||||
<a
|
||||
className="btn"
|
||||
href="https://mp.weixin.qq.com/s/UrnGRks6R-JJ4oZTdt0Xrw"
|
||||
href="/tabs/feed.html"
|
||||
target="_blank"
|
||||
rel="noreferrer">
|
||||
{i18n("support")}👍
|
||||
|
||||
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 40 KiB |
@@ -62,7 +62,7 @@ pnpm install @plasmohq/messaging
|
||||
├── background
|
||||
│ ├── index.ts
|
||||
│ └── messages
|
||||
│ ├── tab.ts
|
||||
│ ├── ping.ts
|
||||
│ └── icon.ts
|
||||
```
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 16 KiB |
@@ -8,28 +8,14 @@
|
||||
github地址:https://github.com/027xiguapi/code-box
|
||||
|
||||
自定义
|
||||
1. 插入自定义样式(css代码)
|
||||
2. 自定义选择下载html
|
||||
3. 自定义选择下载markdown
|
||||
4. 自定义选择下载pdf
|
||||
5. 一键下载所有图片
|
||||
6. 在线编辑markdown
|
||||
|
||||
微信
|
||||
1. 插入自定义样式(css代码)
|
||||
2. 一键下载html
|
||||
3. 一键下载markdown
|
||||
4. 一键下载pdf
|
||||
5. 一键下载所有图片
|
||||
|
||||
掘金
|
||||
1. 插入自定义样式(css代码)
|
||||
2. 一键选择下载html
|
||||
3. 一键选择下载markdown
|
||||
4. 一键选择下载pdf
|
||||
- 插入自定义样式(css代码)
|
||||
- 自定义选择下载html
|
||||
- 自定义选择下载markdown
|
||||
- 自定义选择下载pdf
|
||||
|
||||
CSDN
|
||||
1. 一键下载文章html、pdf或markdown文件
|
||||
1. 一键下载文章html或markdown文件
|
||||
2. 打开任意一个CSDN博客即可开始复制代码
|
||||
3. 未登录CSDN状态下,支持选中代码
|
||||
4. 未登录CSDN状态下,代码右上角按钮一键复制
|
||||
@@ -37,16 +23,12 @@ CSDN
|
||||
6. 未关注博主状态下,不再提示关注博主即可阅读全文,且完整展示文章
|
||||
7. 自动展开代码块
|
||||
8. 移动端屏蔽跳转APP
|
||||
9. 插入自定义样式(css代码)
|
||||
|
||||
|
||||
知乎
|
||||
1. 一键下载文章html、pdf或markdown文件
|
||||
1. 一键下载文章html或markdown文件
|
||||
2. 一键复制代码
|
||||
3. 未登录知乎状态下,不再提示展开阅读全文,且完整展示文章
|
||||
4. 未登录知乎状态下,不会再出现强制登录弹窗
|
||||
5. 插入自定义样式(css代码)
|
||||
|
||||
|
||||
百度
|
||||
1. 一键下载对话框html或markdown文件
|
||||
@@ -57,40 +39,31 @@ CSDN
|
||||
2. 一键复制代码
|
||||
3. 不再提示展开阅读全文,且完整展示文章
|
||||
4. 不会再出现强制登录弹窗
|
||||
6. 插入自定义样式(css代码)
|
||||
|
||||
脚本之家
|
||||
1. 一键下载文章html、pdf或markdown文件
|
||||
1. 一键下载文章html或markdown文件
|
||||
2. 打开任意一个脚本之家博客即可开始复制代码
|
||||
3. 未登录脚本之家状态下,支持选中代码
|
||||
4. 屏蔽广告
|
||||
5. 移动端未登录脚本之家状态下,代码右上角按钮一键复制
|
||||
6. 插入自定义样式(css代码)
|
||||
|
||||
|
||||
博客园
|
||||
- 插入自定义样式(css代码)
|
||||
- 自定义选择下载html
|
||||
- 自定义选择下载markdown
|
||||
- 自定义选择下载pdf
|
||||
1. 一键下载文章html或markdown文件
|
||||
2. 一键复制代码
|
||||
|
||||
51CTO博客
|
||||
1. 一键下载文章html、pdf或markdown文件
|
||||
1. 一键下载文章html或markdown文件
|
||||
2. 未登录51CTO博客状态下,支持选中代码
|
||||
3. 未登录51CTO博客状态下,代码右上角按钮一键复制
|
||||
4. 未登录51CTO博客状态下,不会再出现强制登录弹窗
|
||||
5. 移动端未登录51CTO博客状态下,代码右上角按钮一键复制
|
||||
6. 插入自定义样式(css代码)
|
||||
|
||||
php中文网
|
||||
1. 一键下载文章html、pdf或markdown文件
|
||||
### php中文网
|
||||
1. 一键下载文章html或markdown文件
|
||||
2. 未登录php中文网状态下,支持选中代码
|
||||
3. 未登录php中文网状态下,代码右上角按钮一键复制
|
||||
4. 未登录php中文网状态下,不会再出现强制登录弹窗
|
||||
5. 未登录php中文网状态下,移动端代码右上角按钮一键复制
|
||||
6. 插入自定义样式(css代码)
|
||||
|
||||
|
||||
|
||||
|
||||
火狐说明:
|
||||
|
||||
|
Before Width: | Height: | Size: 101 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 25 KiB |
@@ -1,100 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
<style>
|
||||
.text-gradient {
|
||||
font-size: 48px;
|
||||
margin: auto;
|
||||
text-align: center;
|
||||
/* 设置字体透明 */
|
||||
color: transparent;
|
||||
/* 设置线性渐变,从红色渐变到蓝色 */
|
||||
background-image: linear-gradient(45deg, blue, red);
|
||||
/* 使用 -webkit-background-clip 属性将背景剪裁至文本形状 */
|
||||
-webkit-background-clip: text;
|
||||
/* 非Webkit内核浏览器需要使用标准前缀 */
|
||||
background-clip: text;
|
||||
/* 把当前元素设置为行内块,以便能够应用背景 */
|
||||
}
|
||||
|
||||
.text {
|
||||
text-anchor: middle;
|
||||
dominant-baseline: middle;
|
||||
fill: url(#gradient);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- <svg>
|
||||
<defs>
|
||||
<linearGradient id="gradient">
|
||||
<stop offset="0%" stop-color="#FFCF02" />
|
||||
<stop offset="100%" stop-color="#FF7352" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<text class="text" x="50%" y="50%">为你定制 发现精彩</text>
|
||||
</svg> -->
|
||||
<!-- <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-square-code">
|
||||
<path d="M10 9.5 8 12l2 2.5" />
|
||||
<path d="m14 9.5 2 2.5-2 2.5" />
|
||||
<rect width="18" height="18" x="3" y="3" rx="2" />
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-badge">
|
||||
<linearGradient id="gradient">
|
||||
<stop offset="0%" stop-color="#FFCF02" />
|
||||
<stop offset="100%" stop-color="#FF7352" />
|
||||
</linearGradient>
|
||||
<path class="text"
|
||||
d="M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z" />
|
||||
<path d="M10 9.5 8 12l2 2.5" />
|
||||
<path d="m14 9.5 2 2.5-2 2.5" />
|
||||
</svg> -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-badge">
|
||||
<linearGradient id="gradient">
|
||||
<stop offset="0%" stop-color="#FFCF02" />
|
||||
<stop offset="100%" stop-color="#FF7352" />
|
||||
</linearGradient>
|
||||
<path class="text"
|
||||
d="M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z" />
|
||||
<path d="M10 9.5 8 12l2 2.5" />
|
||||
<path d="m14 9.5 2 2.5-2 2.5" />
|
||||
</svg>
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 124 124" fill="none">
|
||||
<rect width="124" height="124" rx="24" fill="#F97316" />
|
||||
<path
|
||||
d="M19.375 36.7818V100.625C19.375 102.834 21.1659 104.625 23.375 104.625H87.2181C90.7818 104.625 92.5664 100.316 90.0466 97.7966L26.2034 33.9534C23.6836 31.4336 19.375 33.2182 19.375 36.7818Z"
|
||||
fill="white" />
|
||||
<circle cx="63.2109" cy="37.5391" r="18.1641" fill="black" />
|
||||
<rect opacity="0.4" x="81.1328" y="80.7198" width="17.5687" height="17.3876" rx="4"
|
||||
transform="rotate(-45 81.1328 80.7198)" fill="#FDBA74" />
|
||||
</svg>
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke-width="0" fill="#F97316"
|
||||
d="M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z" />
|
||||
<path d="M10 9.5 8 12l2 2.5" stroke="white"/>
|
||||
<path d="m14 9.5 2 2.5-2 2.5" stroke="white"/>
|
||||
</svg>
|
||||
|
||||
<div id="editableDiv" contenteditable="true">这是可编辑的内容。</div>
|
||||
<button onclick="modifyContent()">修改内容</button>
|
||||
<script>
|
||||
function modifyContent() {
|
||||
var editableDiv = document.getElementById('editableDiv');
|
||||
editableDiv.innerHTML = '这是修改后的内容!'; // 修改为新的内容
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,16 +1,16 @@
|
||||
const sharp = require("sharp")
|
||||
const sharp = require('sharp');
|
||||
|
||||
const input = "../assets/icon.png"
|
||||
const input = '../assets/logo.png'
|
||||
|
||||
const output = "../assets/logo.png"
|
||||
const output = '../assets/output.png'
|
||||
|
||||
sharp(input)
|
||||
// .tint({ r: 255, g: 240, b: 16 })
|
||||
.linear(0.8, 1.5)
|
||||
.toFile(output, (err, info) => {
|
||||
if (err) {
|
||||
console.error("处理图片出错:", err)
|
||||
return
|
||||
console.error('处理图片出错:', err);
|
||||
return;
|
||||
}
|
||||
console.log("图片处理完成:", info)
|
||||
})
|
||||
console.log('图片处理完成:', info);
|
||||
});
|
||||
@@ -1,7 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke-width="0" fill="#F97316"
|
||||
d="M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z" />
|
||||
<path d="M10 9.5 8 12l2 2.5" stroke="white"/>
|
||||
<path d="m14 9.5 2 2.5-2 2.5" stroke="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 515 B |
@@ -1,44 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
body {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
background-color: #fff;
|
||||
}
|
||||
div {
|
||||
text-align: center;
|
||||
}
|
||||
img {
|
||||
width: 20%;
|
||||
}
|
||||
p {
|
||||
font-size: 2em;
|
||||
color: #000;
|
||||
font-family: fantasy;
|
||||
}
|
||||
div {
|
||||
font-size: 1em;
|
||||
color: #666;
|
||||
font-family: fantasy;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<img src="./128x128.png" alt="logo" />
|
||||
<p>codebox</p>
|
||||
<div>One-click Code Copying/Downloading Articles</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
Before Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 91 KiB |
|
Before Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 50 KiB |
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"presets": ["@babel/preset-env"]
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
import fetch from "node-fetch"
|
||||
|
||||
class WechatSender {
|
||||
constructor() {
|
||||
this.appid = process.env.WECHAT_APPID
|
||||
this.secret = process.env.WECHAT_SECRET
|
||||
|
||||
if (!this.appid || !this.secret) {
|
||||
const errorMessage =
|
||||
"Error: WECHAT_APPID or WECHAT_SECRET is not set in the environment variables"
|
||||
console.error(errorMessage)
|
||||
throw new Error(errorMessage)
|
||||
}
|
||||
}
|
||||
|
||||
async getAccessToken() {
|
||||
const url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${this.appid}&secret=${this.secret}`
|
||||
const response = await fetch(url)
|
||||
const data = await response.json()
|
||||
if (data.errcode) {
|
||||
throw new Error(`Failed to get access token: ${data.errmsg}`)
|
||||
}
|
||||
return data.access_token
|
||||
}
|
||||
|
||||
async addDraft(accessToken, event) {
|
||||
const url = `https://api.weixin.qq.com/cgi-bin/draft/add?access_token=${accessToken}`
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
articles: [
|
||||
{
|
||||
title: event.title, // 标题
|
||||
author: event.author, // 作者
|
||||
digest: event.digest, // 图文消息的摘要,仅有单图文消息才有摘要,多图文此处为空。如果本字段为没有填写,则默认抓取正文前54个字。
|
||||
content: event.content, // 图文消息的具体内容,支持HTML标签,必须少于2万字符,小于1M,且此处会去除JS,涉及图片url必须来源 "上传图文消息内的图片获取URL"接口获取。外部图片url将被过滤。
|
||||
content_source_url: event.content_source_url, //图文消息的原文地址,即点击“阅读原文”后的URL
|
||||
thumb_media_id: event.thumb_media_id, // 图文消息的封面图片素材id(必须是永久MediaID)
|
||||
need_open_comment: event.need_open_comment, // Uint32 是否打开评论,0不打开(默认),1打开
|
||||
only_fans_can_comment: event.only_fans_can_comment, // Uint32 是否粉丝才可评论,0所有人可评论(默认),1粉丝才可评论
|
||||
pic_crop_235_1: event.pic_crop_235_1, // 封面裁剪为2.35:1规格的坐标字段。
|
||||
pic_crop_1_1: event.pic_crop_1_1 // 封面裁剪为1:1规格的坐标字段,裁剪原理同pic_crop_235_1,裁剪后的图片必须符合规格要求。
|
||||
}
|
||||
]
|
||||
})
|
||||
})
|
||||
const data = await response.json()
|
||||
if (data.errcode) {
|
||||
throw new Error(`Failed to add draft: ${data.errmsg}`)
|
||||
}
|
||||
return data.media_id
|
||||
}
|
||||
|
||||
async publishArticle(accessToken, mediaId) {
|
||||
const url = `https://api.weixin.qq.com/cgi-bin/freepublish/submit?access_token=${accessToken}`
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
media_id: mediaId
|
||||
})
|
||||
})
|
||||
const data = await response.json()
|
||||
if (data.errcode) {
|
||||
throw new Error(`Failed to publish article: ${data.errmsg}`)
|
||||
}
|
||||
return data.publish_id
|
||||
}
|
||||
|
||||
async send(event) {
|
||||
try {
|
||||
const accessToken = await this.getAccessToken()
|
||||
const mediaId = await this.addDraft(accessToken, event)
|
||||
const articleId = await this.publishArticle(accessToken, mediaId)
|
||||
console.log(`Article published successfully. Article ID: ${articleId}`)
|
||||
return articleId
|
||||
} catch (error) {
|
||||
console.error("Error in WechatSender:", error.message)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default WechatSender
|
||||
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"name": "wechat-sender",
|
||||
"version": "1.0.0",
|
||||
"description": "A Node.js module for creating and publishing WeChat articles",
|
||||
"main": "WechatSender.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
|
||||
},
|
||||
"keywords": ["wechat", "article", "publisher"],
|
||||
"author": "Your Name",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"node-fetch": "^3.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/preset-env": "^7.16.11",
|
||||
"jest": "^27.5.1"
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
import dotenv from "dotenv"
|
||||
import express from "express"
|
||||
|
||||
import WechatSender from "./WechatSender.js"
|
||||
|
||||
dotenv.config()
|
||||
|
||||
const app = express()
|
||||
app.use(express.json())
|
||||
|
||||
const wechatSender = new WechatSender()
|
||||
|
||||
app.post("/api/article/send", async (req, res) => {
|
||||
try {
|
||||
const article = req.body
|
||||
const articleId = await wechatSender.send({ ...article })
|
||||
res.json({ success: true, articleId })
|
||||
} catch (error) {
|
||||
console.error("Error sending article:", error)
|
||||
res.status(500).json({ success: false, error: error.message })
|
||||
}
|
||||
})
|
||||
|
||||
app.post("/api/article/submit", async (req, res) => {
|
||||
try {
|
||||
const article = req.body
|
||||
const accessToken = await wechatSender.getAccessToken()
|
||||
const mediaId = await wechatSender.addDraft(accessToken, {
|
||||
...article
|
||||
})
|
||||
res.json({ success: true, mediaId })
|
||||
} catch (error) {
|
||||
console.error("Error submitting article:", error)
|
||||
res.status(500).json({ success: false, error: error.message })
|
||||
}
|
||||
})
|
||||
|
||||
const PORT = process.env.PORT || 3000
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Server is running on port ${PORT}`)
|
||||
})
|
||||
|
||||
export default app
|
||||
@@ -1,64 +0,0 @@
|
||||
import { jest } from "@jest/globals"
|
||||
import request from "supertest"
|
||||
|
||||
import app from "./server.js"
|
||||
import WechatSender from "./WechatSender.js"
|
||||
|
||||
jest.mock("./WechatSender.js")
|
||||
|
||||
describe("Express App", () => {
|
||||
beforeEach(() => {
|
||||
WechatSender.mockClear()
|
||||
})
|
||||
|
||||
test("POST /api/send-article", async () => {
|
||||
const mockSend = jest.fn().mockResolvedValue("mock_article_id")
|
||||
WechatSender.mockImplementation(() => ({
|
||||
send: mockSend
|
||||
}))
|
||||
|
||||
const response = await request(app).post("/api/send-article").send({
|
||||
title: "Test Title",
|
||||
subTitle: "Test Subtitle",
|
||||
content: "Test Content"
|
||||
})
|
||||
|
||||
expect(response.statusCode).toBe(200)
|
||||
expect(response.body).toEqual({
|
||||
success: true,
|
||||
articleId: "mock_article_id"
|
||||
})
|
||||
expect(mockSend).toHaveBeenCalledWith({
|
||||
title: "Test Title",
|
||||
subTitle: "Test Subtitle",
|
||||
content: "Test Content"
|
||||
})
|
||||
})
|
||||
|
||||
test("POST /api/submit-article", async () => {
|
||||
const mockGetAccessToken = jest.fn().mockResolvedValue("mock_access_token")
|
||||
const mockAddDraft = jest.fn().mockResolvedValue("mock_media_id")
|
||||
WechatSender.mockImplementation(() => ({
|
||||
getAccessToken: mockGetAccessToken,
|
||||
addDraft: mockAddDraft
|
||||
}))
|
||||
|
||||
const response = await request(app).post("/api/submit-article").send({
|
||||
title: "Test Title",
|
||||
subTitle: "Test Subtitle",
|
||||
content: "Test Content"
|
||||
})
|
||||
|
||||
expect(response.statusCode).toBe(200)
|
||||
expect(response.body).toEqual({
|
||||
success: true,
|
||||
mediaId: "mock_media_id"
|
||||
})
|
||||
expect(mockGetAccessToken).toHaveBeenCalled()
|
||||
expect(mockAddDraft).toHaveBeenCalledWith("mock_access_token", {
|
||||
title: "Test Title",
|
||||
subTitle: "Test Subtitle",
|
||||
content: "Test Content"
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -16,15 +16,6 @@
|
||||
.valid {
|
||||
color: red;
|
||||
}
|
||||
.summary {
|
||||
.title {
|
||||
font-size: 16px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
.content {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
.contentTitle {
|
||||
margin: 15px 0 10px 0;
|
||||
}
|
||||
|
||||
@@ -2,31 +2,24 @@ import { ThemeProvider } from "~theme"
|
||||
|
||||
import "~index.css"
|
||||
|
||||
import { DownloadOutlined, PushpinOutlined } from "@ant-design/icons"
|
||||
import qrcodeUrl from "raw:~/public/wx/gzh.jpg"
|
||||
import {
|
||||
DownloadOutlined,
|
||||
KeyOutlined,
|
||||
PushpinOutlined
|
||||
} from "@ant-design/icons"
|
||||
import dayjs from "dayjs"
|
||||
import { useRef, useState } from "react"
|
||||
|
||||
import { sendToContentScript } from "@plasmohq/messaging"
|
||||
import { useMessage } from "@plasmohq/messaging/dist/hook"
|
||||
import { useStorage } from "@plasmohq/storage/dist/hook"
|
||||
|
||||
import ValidateContent from "~component/contents/validateContent"
|
||||
import { verifyTOTP } from "~utils/2FA"
|
||||
|
||||
import styles from "./index.module.scss"
|
||||
|
||||
function IndexSidePanel() {
|
||||
const [codes] = useStorage("app-codes", [])
|
||||
const [summary, setSummary] = useStorage("app-summary", {
|
||||
title: "",
|
||||
score: "",
|
||||
content: ""
|
||||
})
|
||||
|
||||
useMessage((req: any, res: any) => {
|
||||
if (req.name === "isSidePanelOpen") {
|
||||
return true
|
||||
}
|
||||
if (req.name == "sidepanel") {
|
||||
req.body.active || window.close()
|
||||
}
|
||||
})
|
||||
|
||||
function pinCode(index) {
|
||||
sendToContentScript({ name: `custom-scrollIntoViewCode`, body: { index } })
|
||||
@@ -41,19 +34,9 @@ function IndexSidePanel() {
|
||||
<div className={`${styles.sidepanel}`}>
|
||||
<div className="wechat">
|
||||
<h1>微信公众号</h1>
|
||||
<img style={{ margin: "auto" }} src={qrcodeUrl} alt="微信公众号" />
|
||||
<ValidateContent></ValidateContent>
|
||||
</div>
|
||||
<div className="content">
|
||||
{summary.content ? (
|
||||
<div className="summary">
|
||||
<div className="title">
|
||||
{summary.title}(评分:{summary.score})
|
||||
</div>
|
||||
<div className="content">{summary.content}</div>
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
<h1 className="contentTitle">导航</h1>
|
||||
{codes.map((code, index) => (
|
||||
<div
|
||||
|
||||
@@ -2,7 +2,7 @@ import chromeUrl from "raw:~/public/webstore/1723513894421.jpg"
|
||||
import githubUrl from "raw:~/public/webstore/1724640034462.jpg"
|
||||
import edgeUrl from "raw:~/public/webstore/1724640161752.jpg"
|
||||
import firefoxUrl from "raw:~/public/webstore/img.png"
|
||||
import qrcodeUrl from "raw:~/public/wx/gzh.jpg"
|
||||
import qrcodeUrl from "raw:~/public/wx/qrcode_wx.jpg"
|
||||
|
||||
import styles from "./feed.module.scss"
|
||||
|
||||
|
||||