mirror of
https://github.com/027xiguapi/code-box.git
synced 2026-09-29 10:48:27 +00:00
生成二维码海报
This commit is contained in:
+5
-33
@@ -13,42 +13,14 @@ 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
|
||||
// // })
|
||||
// // }
|
||||
// })()
|
||||
})
|
||||
|
||||
+73
-12
@@ -5,16 +5,16 @@ import type {
|
||||
PlasmoGetShadowHostId,
|
||||
PlasmoGetStyle
|
||||
} from "plasmo"
|
||||
import { useEffect, useRef, type FC } from "react"
|
||||
import qrcodeUrl from "raw:~/public/wx/qrcode_wx.jpg"
|
||||
import React, { useEffect, useRef, useState, type FC } from "react"
|
||||
|
||||
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 { 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 Turndown from "~utils/turndown"
|
||||
@@ -61,15 +61,44 @@ const HOST_ID = "codebox-juejin"
|
||||
export const getShadowHostId: PlasmoGetShadowHostId = () => HOST_ID
|
||||
|
||||
export const getOverlayAnchor: PlasmoGetOverlayAnchor = async () =>
|
||||
document.querySelector("article.article .article-title")
|
||||
document.querySelector("#juejin")
|
||||
|
||||
export const getStyle: PlasmoGetStyle = () => TagBtnStyle()
|
||||
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: "1.2rem",
|
||||
marginBottom: "3px"
|
||||
}
|
||||
}
|
||||
|
||||
const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
const [parseContent, setParseContent] = useParseMarkdown()
|
||||
const [showTag, setShowTag] = useStorage<boolean>("juejin-showTag", true)
|
||||
const [cssCode, runCss] = useCssCodeHook("juejin")
|
||||
const [content, setContent] = useEditMarkdown()
|
||||
const [isShow, setIsShow] = useState(true)
|
||||
|
||||
useMessage(async (req, res) => {
|
||||
if (req.name == "juejin-isShow") {
|
||||
@@ -89,6 +118,13 @@ 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.article")
|
||||
if (article) {
|
||||
@@ -119,13 +155,38 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
setParseContent(dom)
|
||||
}
|
||||
|
||||
return showTag ? (
|
||||
<Tags
|
||||
onEdit={editMarkdown}
|
||||
onDownload={downloadMarkdown}
|
||||
onPrint={downloadPdf}
|
||||
onParse={parseMarkdown}
|
||||
/>
|
||||
function onClose() {
|
||||
setIsShow(false)
|
||||
}
|
||||
|
||||
return showTag && isShow ? (
|
||||
<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={getDescription}>文章摘要</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={() => makerQRPost()}>生成海报</a>
|
||||
</div>
|
||||
<a style={style.item} href="https://www.code-box.fun" target="_blank">
|
||||
帮助
|
||||
</a>
|
||||
</div>
|
||||
) : (
|
||||
<></>
|
||||
)
|
||||
|
||||
+6
-7
@@ -13,9 +13,10 @@ import React, { useEffect, useState, type FC } from "react"
|
||||
import { useMessage } from "@plasmohq/messaging/hook"
|
||||
import { useStorage } from "@plasmohq/storage/dist/hook"
|
||||
|
||||
import { i18n, saveHtml, saveMarkdown } from "~tools"
|
||||
import { 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 Turndown from "~utils/turndown"
|
||||
@@ -139,8 +140,6 @@ const style = {
|
||||
}
|
||||
}
|
||||
|
||||
console.log(8878878)
|
||||
|
||||
const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
const [parseContent, setParseContent] = useParseMarkdown()
|
||||
const [showTag, setShowTag] = useStorage<boolean>("weixin-showTag", true)
|
||||
@@ -320,10 +319,10 @@ const PlasmoOverlay: FC<PlasmoCSUIProps> = ({ anchor }) => {
|
||||
<div style={style.item}>
|
||||
<a onClick={() => downloadImages()}>下载所有图片</a>
|
||||
</div>
|
||||
<a
|
||||
style={{ color: "#000" }}
|
||||
href="https://www.code-box.fun"
|
||||
target="_blank">
|
||||
<div style={style.item}>
|
||||
<a onClick={() => makerQRPost()}>生成海报</a>
|
||||
</div>
|
||||
<a style={style.item} href="https://www.code-box.fun" target="_blank">
|
||||
帮助
|
||||
</a>
|
||||
</div>
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "code-box",
|
||||
"displayName": "__MSG_extensionName__",
|
||||
"version": "1.1.1",
|
||||
"version": "1.1.2",
|
||||
"description": "__MSG_extensionDescription__",
|
||||
"author": "027xiguapi. <458813868@qq.com>",
|
||||
"scripts": {
|
||||
@@ -32,12 +32,12 @@
|
||||
"antd": "^5.21.1",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dayjs": "^1.11.12",
|
||||
"file-save": "^0.2.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"html2canvas": "^1.4.1",
|
||||
"jssha": "^3.3.1",
|
||||
"jszip": "^3.10.1",
|
||||
"plasmo": "0.89.4",
|
||||
"qrcode": "^1.5.4",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"uuid": "^10.0.0"
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
import { saveAs } from "file-saver"
|
||||
import QRCode from "qrcode"
|
||||
|
||||
interface Position {
|
||||
x: number
|
||||
y: number
|
||||
}
|
||||
|
||||
export default function makerQRCodeImg() {
|
||||
const qrcodepostmaker = document.createElement("canvas")
|
||||
qrcodepostmaker.id = "qrcodepostmaker"
|
||||
qrcodepostmaker.style.display = "none"
|
||||
document.body.appendChild(qrcodepostmaker)
|
||||
|
||||
// 文本换行处理
|
||||
const textComputer = (
|
||||
text: string,
|
||||
style: string,
|
||||
width: number,
|
||||
ctx: CanvasRenderingContext2D
|
||||
): string[] => {
|
||||
if (text.replace(/\s/g, "").length === 0) {
|
||||
return []
|
||||
}
|
||||
ctx.font = style
|
||||
let temp = 0
|
||||
const row: string[] = []
|
||||
for (let i = 0; i <= text.length; i++) {
|
||||
if (ctx.measureText(text.substring(temp, i)).width >= width) {
|
||||
row.push(text.substring(temp, i - 1))
|
||||
temp = i - 1
|
||||
} else if (i === text.length) {
|
||||
row.push(text.substring(temp, i))
|
||||
}
|
||||
}
|
||||
return row
|
||||
}
|
||||
|
||||
// 绘制文本
|
||||
const textWriter = (
|
||||
textArr: string[],
|
||||
Style: string,
|
||||
align: CanvasTextAlign,
|
||||
color: string,
|
||||
borderColor: string,
|
||||
fontSize: number,
|
||||
lineHeight: number,
|
||||
pos: Position,
|
||||
ctx: CanvasRenderingContext2D
|
||||
): Position => {
|
||||
ctx.font = Style
|
||||
ctx.textAlign = align
|
||||
ctx.fillStyle = color
|
||||
ctx.strokeStyle = borderColor
|
||||
for (const text of textArr) {
|
||||
pos.y += fontSize * lineHeight
|
||||
ctx.fillText(text, pos.x, pos.y)
|
||||
}
|
||||
return pos
|
||||
}
|
||||
|
||||
// 生成海报
|
||||
const makerQRPost = (): void => {
|
||||
const canvas = document.querySelector<HTMLCanvasElement>("#qrcodepostmaker")
|
||||
const ctx = canvas.getContext("2d")
|
||||
if (!ctx) return
|
||||
|
||||
const QRCodeData = ctx.getImageData(0, 0, canvas.width, canvas.height)
|
||||
const title = document.title
|
||||
const desc = document.head.querySelector('meta[name="description"]')
|
||||
? document.head.querySelector<HTMLMetaElement>(
|
||||
'meta[name="description"]'
|
||||
)!.content
|
||||
: ""
|
||||
const cardWidth = 360
|
||||
const lineHeight = 1.6
|
||||
const margin = 36
|
||||
const titleStyle = 'Bold 18px "Microsoft YaHei"'
|
||||
const descStyle = '16px "Microsoft YaHei"'
|
||||
|
||||
const titleArray = textComputer(
|
||||
title,
|
||||
titleStyle,
|
||||
cardWidth - margin * 2,
|
||||
ctx
|
||||
)
|
||||
const descArray = textComputer(desc, descStyle, cardWidth - margin * 2, ctx)
|
||||
|
||||
const cardHeight =
|
||||
margin * 2.5 +
|
||||
18 * titleArray.length * lineHeight +
|
||||
16 * descArray.length * lineHeight +
|
||||
(descArray.length ? margin / 2 : 0) +
|
||||
300
|
||||
|
||||
canvas.width = cardWidth
|
||||
canvas.height = cardHeight
|
||||
|
||||
const myGradient = ctx.createLinearGradient(0, 0, 0, cardHeight)
|
||||
myGradient.addColorStop(0, "#2980B9")
|
||||
myGradient.addColorStop(0.5, "#6DD5FA")
|
||||
myGradient.addColorStop(1, "#FFFFFF")
|
||||
|
||||
ctx.fillStyle = myGradient
|
||||
ctx.fillRect(0, 0, cardWidth, cardHeight)
|
||||
ctx.fillStyle = "#FFFFFF"
|
||||
|
||||
ctx.beginPath()
|
||||
ctx.arc(margin * 0.4, cardHeight - margin * 5, margin, 0, Math.PI * 2, true)
|
||||
ctx.arc(
|
||||
cardWidth - margin * 0.4,
|
||||
cardHeight - margin * 3,
|
||||
margin * 0.8,
|
||||
0,
|
||||
Math.PI * 2,
|
||||
true
|
||||
)
|
||||
ctx.fillRect(0, cardHeight - margin * 5, cardWidth / 2, margin * 5)
|
||||
ctx.fillRect(
|
||||
cardWidth / 2,
|
||||
cardHeight - margin * 3,
|
||||
cardWidth / 2,
|
||||
margin * 3
|
||||
)
|
||||
ctx.fill()
|
||||
|
||||
const titleEnd = textWriter(
|
||||
titleArray,
|
||||
titleStyle,
|
||||
"center",
|
||||
"black",
|
||||
"rgba(255, 255, 255, 0.6)",
|
||||
18,
|
||||
lineHeight,
|
||||
{ x: cardWidth / 2, y: margin },
|
||||
ctx
|
||||
)
|
||||
const descEnd = textWriter(
|
||||
descArray,
|
||||
descStyle,
|
||||
"left",
|
||||
"black",
|
||||
"rgba(255, 255, 255, 0.6)",
|
||||
16,
|
||||
lineHeight,
|
||||
{ x: margin, y: titleEnd.y + margin / 2 },
|
||||
ctx
|
||||
)
|
||||
|
||||
ctx.fillStyle = "white"
|
||||
ctx.fillRect((cardWidth - 288) / 2, descEnd.y + margin - 24, 288, 288)
|
||||
ctx.putImageData(QRCodeData, (cardWidth - 256) / 2, descEnd.y + margin)
|
||||
|
||||
textWriter(
|
||||
["(长按识别二维码进行访问)"],
|
||||
descStyle,
|
||||
"center",
|
||||
"rgba(0, 0, 0, 0.6)",
|
||||
"rgba(255, 255, 255, 0.6)",
|
||||
16,
|
||||
lineHeight,
|
||||
{ x: cardWidth / 2, y: descEnd.y + margin + 256 },
|
||||
ctx
|
||||
)
|
||||
|
||||
saveAs(canvas.toDataURL("image/png"), title + ".png")
|
||||
qrcodepostmaker.parentNode?.removeChild(qrcodepostmaker)
|
||||
}
|
||||
|
||||
let tryTimes = 30
|
||||
const makeQRCode = window.setInterval(() => {
|
||||
try {
|
||||
QRCode.toCanvas(
|
||||
document.getElementById("qrcodepostmaker"),
|
||||
window.location.href,
|
||||
{ width: 260, errorCorrectionLevel: "Q" },
|
||||
(error) => {
|
||||
if (error) {
|
||||
console.log(error)
|
||||
return
|
||||
}
|
||||
makerQRPost()
|
||||
}
|
||||
)
|
||||
window.clearInterval(makeQRCode)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
tryTimes--
|
||||
if (!tryTimes) {
|
||||
window.clearInterval(makeQRCode)
|
||||
alert("没能成功载入功能库,请刷新重试~")
|
||||
}
|
||||
}
|
||||
}, 200)
|
||||
}
|
||||
Reference in New Issue
Block a user